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引擎代码,但代码相同: