2014-06-23 59 views
1

柱說,我有以下數據集計數明顯不同的字符在

Column1 (VarChar(50 or something)) 
Elias 
Sails 
Pails 
Plane 
Games 

我想從這個塔中以產生如下設置:

LETTER  COUNT 
E   3 
L   4 
I   3 
A   5 
S   5 
And So On... 

一個解決方案我想到的將所有字符串合併爲一個字符串,然後計算該字符串中每個字母的實例,但感覺馬虎。

這是一個比其他任何事情都好奇的練習,但是,有沒有辦法用SQL計算數據集中所有不同的字母數?

CREATE TABLE tblLetter 
(
    letter varchar(1) 
); 

INSERT INTO tblLetter ([letter]) 
VALUES 
    ('a'), 
    ('b'), 
    ('c'), 
    ('d'); -- etc 

然後,你可以加入letters到表數據所在的位置像字母:

select l.letter, count(n.col) Total 
from tblLetter l 
inner join names n 
    on n.col like '%'+l.letter+'%' 
group by l.letter; 

回答

2

我會通過創建你的信類似的表做到這一點SQL Fiddle with Demo。如果您創建的字母表,這樣

| LETTER | TOTAL | 
|--------|-------| 
|  a |  5 | 
|  e |  3 | 
|  g |  1 | 
|  i |  3 | 
|  l |  4 | 
|  m |  1 | 
|  p |  2 | 
|  s |  4 | 
1

create table letter (ch char(1)); 
insert into letter(ch) values ('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H') 
,('I'),('J'),('K'),('L'),('M'),('N'),('O'),('P') 
,('Q'),('R'),('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z'); 

你可以用交叉做加盟,像這樣:這會給出一個結果

select ch, SUM(len(str) - len(replace(str,ch,''))) 
from letter 
cross join test -- <<== test is the name of the table with the string 
group by ch 
having SUM(len(str) - len(replace(str,ch,''))) <> 0 

Here is a running demo on sqlfiddle.

你可以做到這一點,而無需通過在查詢中嵌入字母列表來定義表格自我,但通過信件交叉加入和分組的想法將保持不變。

注:see this answerSUM內表達的解釋。

+0

但是,爲什麼只有在分組之後纔會過濾掉不相關的結果? '... WHERE len(str) - len(replace(str,ch,''))<> 0 GROUP BY ch'可能證明更快。 –

+0

@AndriyM這應該沒有什麼區別:在任何一種情況下,表達式都會被評估一次,每個單詞/字符對進入'SUM';這就是真正的開支。 「GROUP BY」非常便宜後過濾掉零。事實上,它可能比WHERE條款更便宜,因爲這會導致更少的零檢查(正好是26,而不是'26 * wordCount')。 – dasblinkenlight

0

即使您打開了區分大小寫,這也應該可以工作。

的設置:

CREATE TABLE _test (Column1 VARCHAR (50)) 

INSERT _test (Column1) VALUES ('Elias'),('Sails'),('Pails'),('Plane'),('Games') 

工作:

DECLARE @counter AS INT 
DECLARE @results TABLE (LETTER VARCHAR(1),[COUNT] INT) 

SET @counter=65 --ascii value for 'A' 

WHILE (@counter <=90) -- ascii value for 'Z' 
BEGIN 
    INSERT @results (LETTER,[COUNT]) 
    SELECT CHAR(@counter),SUM(LEN(UPPER(Column1)) - LEN(REPLACE(UPPER(Column1), CHAR(@counter),''))) FROM _test 
    SET @[email protected]+1 
END 

SELECT * FROM @results WHERE [Count]>0 
0

這往往是非常有用的一個範圍或序列表,可讓您連續序列號的大運行的來源,像這樣的覆蓋範圍-100,000 – + 100,000。

drop table dbo.range 
go 
create table dbo.range 
(
    id int not null primary key clustered , 
) 
go 

set nocount on 
go 

declare @i int = -100000 
while (@i <= +100000) 
begin 
    if (@i > 0 and @i % 1000 = 0) print convert(varchar,@i) + ' rows' 
    insert dbo.range values (@i) 
    set @i = @i + 1 
end 
go 

set nocount off 
go 

一旦你有這樣一個表,你可以做這樣的事情:

select character = substring(t.some_column , r.id , 1) , 
     frequency = count(*) 
from dbo.some_table t 
join dbo.range  r on r.id between 1 and len(t.some_column) 
group by substring(t.some_column , r.id , 1) 
order by 1 

如果你想確保不區分大小寫,只是混在所需upper()lower()

select character = upper(substring(t.some_column , r.id , 1)) , 
     frequency = count(*) 
from dbo.some_table t 
join dbo.range  r on r.id between 1 and len(t.some_column) 
group by upper(substring(t.some_column , r.id , 1)) 
order by 1 

鑑於您的樣品數據:

create table dbo.some_table 
(
    some_column varchar(50) not null 
) 
go 

insert dbo.some_table values ('Elias') 
insert dbo.some_table values ('Sails') 
insert dbo.some_table values ('Pails') 
insert dbo.some_table values ('Plane') 
insert dbo.some_table values ('Games') 
go 

上述後者查詢產生以下結果:

character frequency 
    A   5 
    E   3 
    G   1 
    I   3 
    L   4 
    M   1 
    N   1 
    P   2 
    S   5 
1

對我來說,這是一個CTE幾乎量身定製的一個問題(感謝,尼古拉斯·凱里,原創,我的小提琴這裏:http://sqlfiddle.com/#!3/44f77/8):

WITH cteLetters 
AS 
(
    SELECT 
       1 AS CharPos, 
       str, 
       MAX(LEN(str)) AS MaxLen, 
       SUBSTRING(str, 1, 1) AS Letter 
    FROM 
       test 
    GROUP BY 
       str, 
       SUBSTRING(str, 1, 1) 

    UNION ALL 

    SELECT 
       CharPos + 1, 
       str, 
       MaxLen, 
       SUBSTRING(str, CharPos + 1, 1) AS Letter 
    FROM 
       cteLetters 
    WHERE 
       CharPos + 1 <= MaxLen 
) 

SELECT 
      UPPER(Letter) AS Letter, 
      COUNT(*) CountOfLetters 
FROM 
      cteLetters 
GROUP BY 
      Letter 
ORDER BY 
      Letter; 

使用CTE來計算字符位置並解構每個字符串。然後你可以從CTE本身進行聚合。不需要額外的表格或任何東西。