2009-10-21 3 views
0

Я хотел бы запустить запрос, который для данного поля будет считать экземпляры определенного символа.Могу ли я выбрать отдельную/группу по символам в поле в SQL?

Например, если у меня была таблица под названием «Друзья» с полем «Имена», содержащей строки: Эдвард, Джеймс, Майк. Я бы получить выход:

A 2, D 2, E 3, I 1, и так далее ...

ответ

2

Общий ответ в том, что вам нужно разделить каждое имя в таблицу составных символов, затем подсчитайте их.

Вы не упомянули, какие РСУБД вы используете. Ответ немного зависит от механизма базы данных.

Например, это будет работать на SQL 2005+:

DECLARE @friends TABLE (NAMES VARCHAR(30)) 
DECLARE @maxLen INT 

INSERT @friends (NAMES) 
SELECT 'Edward' 
UNION SELECT 'James' 
UNION SELECT 'Mike' 

SELECT @maxLen = MAX(LEN(NAMES)) FROM @friends 

;WITH numsCte 
AS 
( 
     --dynamic numbers table. If you have a numbers table in your database 
     --use that instead, as it will be more efficient. 
     SELECT 1 AS n 
     UNION ALL 
     SELECT n+1 FROM numsCte 
     WHERE n < @maxLen 
) 
,charCTE 
AS 
( 
     --split the string into a dataset 
     SELECT * 
     FROM numsCte AS nm 
     CROSS APPLY (SELECT NAMES, SUBSTRING(NAMES, n, 1) AS splitChar 
        FROM @friends 
        ) AS st 
     WHERE splitChar > '' 
) 
SELECT UPPER(splitChar) AS letter 
     ,COUNT(1) AS cnt 
FROM charCTE 
GROUP BY splitChar 
ORDER BY splitChar 

Но почти наверняка не будет работать на любых других СУБД.

+0

+1 Вы можете опустить NAMES из подзапроса CROSS APPLY – Andomar

+0

Я использую SQL 2005, так что это прекрасно. Благодаря! – theaxe

0

Один из способов заключается в использовании временной таблицы, и заполнить его в цикле WHILE:

declare @letters table (letter varchar(1)) 
declare @pos int 
set @pos = 1 
while 1=1 
    begin 
    insert into @letters 
    select substring(name,@pos,1) 
    from @names 
    where len(name) >= @pos 

    if @@rowcount = 0 
     break 

    set @pos = @pos + 1 
    end 

select letter, count(*) 
from @letters 
group by letter 

Другой способ заключается в создании списка допустимых позиций символов во временной таблице, или, как в данном примере, с рекурсивным общего табличного выражения (CTE):

declare @maxLen int 
select @maxLen = max(len(name)) from @names 
;WITH CharPositions (i) AS ( 
    select 1 
    union all 
    select i+1 
    from CharPositions 
    where i < @maxLen 
) 
select substring(n.name,cp.i,1), count(*) 
from @names n 
inner join CharPositions cp on cp.i <= len(n.name) 
group by substring(n.name,cp.i,1) 

Я протестировали образцы кода против этого набора данных:

declare @names table (name varchar(max)) 
insert into @names values ('abc') 
insert into @names values ('def') 
insert into @names values ('def') 
insert into @names values ('g') 
insert into @names values ('g') 
insert into @names values ('g')