Sql 列中不同字符的计数

Sql 列中不同字符的计数,sql,sql-server,count,distinct-values,Sql,Sql Server,Count,Distinct Values,假设我有以下数据集 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... 我想到的一个解决方案是将所有字符串组合成一个字符串,然后计算该字符串中字母的每个实例,但这感觉很马虎 这与其说是出于好奇,

假设我有以下数据集

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
然后,您可以将这些字母连接到您的表中,您的数据如下所示:

select l.letter, count(n.col) Total
from tblLetter l
inner join names n
  on n.col like '%'+l.letter+'%'
group by l.letter;
看。这将产生一个结果:

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

为此,我将创建一个包含您的信件的表格,类似于:

CREATE TABLE tblLetter
(
  letter varchar(1)
);

INSERT INTO tblLetter ([letter])
VALUES
    ('a'),
    ('b'),
    ('c'),
    ('d'); -- etc
然后,您可以将这些字母连接到您的表中,您的数据如下所示:

select l.letter, count(n.col) Total
from tblLetter l
inner join names n
  on n.col like '%'+l.letter+'%'
group by l.letter;
看。这将产生一个结果:

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

如果创建字母表,如下所示:

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
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
您可以使用交叉连接来完成此操作,如下所示:

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
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
通过将字母列表嵌入查询本身,您可以在不定义表的情况下实现这一点,但按字母交叉连接和分组的想法将保持不变


注:用于解释总和中的表达式。

如果创建字母表,如下所示:

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
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
您可以使用交叉连接来完成此操作,如下所示:

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
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
通过将字母列表嵌入查询本身,您可以在不定义表的情况下实现这一点,但按字母交叉连接和分组的想法将保持不变


注意:对于SUM中表达式的解释。

即使启用了区分大小写功能,也应该可以使用此选项

设置:

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 @counter=@counter+1
END

SELECT * FROM @results WHERE [Count]>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 @counter=@counter+1
END

SELECT * FROM @results WHERE [Count]>0

有一个范围表或序列表通常很有用,它可以为您提供大量连续序列号的来源,比如这个覆盖范围为-100000–+100000的表

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
如果要确保不区分大小写,只需混合所需的上下颜色:

根据您的示例数据:

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

有一个范围表或序列表通常很有用,它可以为您提供大量连续序列号的来源,比如这个覆盖范围为-100000–+100000的表

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
如果要确保不区分大小写,只需混合所需的上下颜色:

根据您的示例数据:

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

对我来说,这几乎是一个为CTE量身定做的问题。谢谢尼古拉斯·凯里,谢谢你的原创作品,我的小提琴::


使用CTE计算字符位置并解构每个字符串。然后,您可以从CTE本身进行聚合。不需要额外的桌子或任何东西。

对我来说,这是一个几乎为CTE量身定做的问题。谢谢尼古拉斯·凯里,我的小提琴原版在这里:


使用CTE计算字符位置并解构每个字符串。然后,您可以从CTE本身进行聚合。不需要额外的表格或任何东西。

但是为什么只在分组之后而不是之前过滤掉不相关的结果呢。。。其中lenstr-lenreplacestr,ch,0 GROUP BY ch可能会更快。@AndriyM这应该不会有太大区别:在任何一种情况下,表达式都会对每个单词/字符对进行一次求值,以进入总和;这才是真正的花费所在。分组后过滤掉零是非常便宜的。事实上,它可能会比WHERE子句便宜,因为这会导致更少的零检查,精确到26,而不是26*wordCount。但是为什么只在分组之后而不是之前过滤掉不相关的结果呢。。。其中lenstr-lenreplacestr,ch,0 GROUP BY ch可能会更快。@AndriyM这应该不会有太大区别:在任何一种情况下,表达式都会对每个单词/字符对进行一次求值,以进入总和;这才是真正的花费所在。分组后过滤掉零是非常便宜的。事实上,它可能会比WHERE子句便宜,因为这会减少零检查次数,而不是26*wordCount。您好,我正在尝试您的解决方案,但仍然不确定在查询cteLetters时从何处获取字符。我尝试了你的sqlfiddle示例,但似乎没有work@noorh您好,这些字母来自构建部分中设置的表测试。检查sqlfiddle链接,现在更新为使用SQL Server 2017引擎代码,尽管:您好,我正在尝试您的解决方案,但仍然不确定在查询cteLetters时从何处获取字符。我尝试了你的sqlfiddle示例,但似乎没有work@noorh您好,这些字母来自构建部分中设置的表测试。检查sqlfiddle链接,该链接现已更新为使用SQL Server 2017引擎代码,但代码相同: