2010-05-27 20 views
13

¿Hay alguna forma elegante en SQL Server para encontrar todos los caracteres distintos en una única columna varchar (50) en todas las filas?SQL: cómo obtener todos los caracteres distintos en una columna, en todas las filas

puntos de bonificación si se puede hacer sin cursores :)

Por ejemplo, dicen mis datos contiene 3 filas:

productname 
----------- 
product1 
widget2 
nicknack3 

El inventario de caracteres distinta sería "productwigenka123"

+0

¿Es importante el orden de los caracteres? –

+0

No, los caracteres se pueden devolver en cualquier orden. – frankadelic

Respuesta

2

Dado que su columna es varchar, significa que solo puede almacenar caracteres de los códigos 0 a 255, en cualquier página de códigos que tenga. Si solo usa el rango de código ASCII 32-128, entonces simplemente puede ver si tiene alguno de los caracteres 32-128, uno por uno. La siguiente consulta hace que, mirando en sys.objects.name:

with cteDigits as (
    select 0 as Number 
    union all select 1 as Number 
    union all select 2 as Number 
    union all select 3 as Number 
    union all select 4 as Number 
    union all select 5 as Number 
    union all select 6 as Number 
    union all select 7 as Number 
    union all select 8 as Number 
    union all select 9 as Number) 
, cteNumbers as (
    select U.Number + T.Number*10 + H.Number*100 as Number 
    from cteDigits U 
    cross join cteDigits T 
    cross join cteDigits H) 
, cteChars as (
    select CHAR(Number) as Char 
    from cteNumbers 
    where Number between 32 and 128) 
select cteChars.Char as [*] 
from cteChars 
cross apply (
    select top(1) * 
    from sys.objects 
    where CHARINDEX(cteChars.Char, name, 0) > 0) as o 
for xml path(''); 
1

Si tiene una tabla Numbers o Tally que contiene una lista secuencial de enteros, puede hacer algo como:

Select Distinct '' + Substring(Products.ProductName, N.Value, 1) 
From dbo.Numbers As N 
    Cross Join dbo.Products 
Where N.Value <= Len(Products.ProductName) 
For Xml Path('') 

Si está utilizando SQL Server 2005 y más allá, se puede generar la tabla de números sobre la marcha utilizando un CTE:

With Numbers As 
    (
    Select Row_Number() Over (Order By c1.object_id) As Value 
    From sys.columns As c1 
     Cross Join sys.columns As c2 
    ) 
Select Distinct '' + Substring(Products.ProductName, N.Value, 1) 
From Numbers As N 
    Cross Join dbo.Products 
Where N.Value <= Len(Products.ProductName) 
For Xml Path('') 
17

Aquí es una consulta que devuelve cada personaje como una fila separada, junto con el número de ocurrencias . Suponiendo que se llama su mesa 'Productos'

WITH ProductChars(aChar, remain) AS (
    SELECT LEFT(productName,1), RIGHT(productName, LEN(productName)-1) 
     FROM Products WHERE LEN(productName)>0 
    UNION ALL 
    SELECT LEFT(remain,1), RIGHT(remain, LEN(remain)-1) FROM ProductChars 
     WHERE LEN(remain)>0 
) 
SELECT aChar, COUNT(*) FROM ProductChars 
GROUP BY aChar 

Para combinar todos ellos a una sola fila, (como se indica en la pregunta), cambie la final SELECT a

SELECT aChar AS [text()] FROM 
    (SELECT DISTINCT aChar FROM ProductChars) base 
FOR XML PATH('') 

Lo anterior utiliza un buen truco Encontré here, que emula el GROUP_CONCAT de MySQL.

El primer nivel de recursión se desenrolla para que la consulta no devuelva cadenas vacías en la salida.

+0

Obteniendo "La declaración finalizada. La recursión máxima 100 se ha agotado antes de completar la declaración". – Riga

3

Utilice esta (deberá funcionar en cualquier RDBMS CTE-capaz):

create table prod as 
select x.v from (values('product1'),('widget2'),('nicknack3')) as x(v); 

Consulta de prueba:

with a as 
(
    select v, '' as x, 0 as n from prod 
    union 
    select v, substring(v,n+1,1) as x, n+1 as n from a where n < len(v) 
) 
select v, x, n from a -- where n > 0 
order by v, n 

Consulta final:

with a as 
(
    select v, '' as x, 0 as n from prod 
    union 
    select v, substring(v,n+1,1) as x, n+1 as n from a where n < len(v) 
) 
select distinct x from a where n > 0 
order by x 

Versión de Oracle:

with a(v,x,n) as 
(
    select v, '' as x, 0 as n from prod 
    union all 
    select v, substr(v,n+1,1) as x, n+1 as n from a where n < length(v) 
) 
select distinct x from a where n > 0 
Cuestiones relacionadas