T-Sql计算多行的字符串序列

时间:2012-04-04 08:41:15

标签: sql gaps-and-islands

如何在sql中找到多行数据的子集?

我想在找到另一个字符串之前计算字符串(或数字)的出现次数,然后计算此字符串在找到另一个字符串之前出现的次数。 所有这些字符串都可以按随机顺序排列。

这就是我想要实现的目标:

我有一个包含一列(columnx)的表,其数据如下:

A
A
B
C
A
B
B

我想从查询中得到的结果应该是这样的:

2 A
1 B
1 C
1 A
2 B

这在sql中是否可行?或者只是编写一个小的C#应用​​程序来做这件事会更容易吗?

3 个答案:

答案 0 :(得分:3)

根据您的评论,您可以添加一个明确定义columnx值的顺序的列,您可以尝试以下查询(前提是您使用的SQL产品支持CTE和排名函数):

WITH marked AS (
  SELECT
    columnx,
    sortcolumn,
    grp = ROW_NUMBER() OVER (                     ORDER BY sortcolumn)
        - ROW_NUMBER() OVER (PARTITION BY columnx ORDER BY sortcolumn)
  FROM data
)
SELECT
  columnx,
  COUNT(*)
FROM marked
GROUP BY
  columnx,
  grp
ORDER BY
  MIN(sortcolumn)
;

您可以在工作on SQL Fiddle中看到该方法。

如果sortcolumn是一个保证没有间隙的自动增量整数列,则可以用ROW_NUMBER()替换第一个sortcolumn表达式。但是,我想,这一般无法得到保证。此外,您可能确实想要对时间戳进行排序而不是整数。

答案 1 :(得分:1)

我认为你不能用一个选择来做到这一点。 您可以使用AdventureWorks游标:

create table my_Strings
(
my_string varchar(50)
)


insert into my_strings values('A'),('A'),('B'),('C'),('A'),('B'),('B') -- this method will only work on SQL Server 2008

--select my_String from my_strings 

declare @temp_result table(
string varchar(50),
nr int)

declare @myString varchar(50)
declare @myLastString varchar(50)
declare @nr int

set @myLastString='A' --set this with the value of your FIRST string  on the table
set @nr=0

DECLARE string_cursor CURSOR
FOR 
SELECT my_string as aux_column FROM my_strings  

OPEN string_cursor
FETCH NEXT FROM string_cursor into @myString
WHILE @@FETCH_STATUS = 0 BEGIN
    if (@myString = @myLastString) begin
        set @nr=@nr+1
        set @myLastString=@myString
    end else begin
        insert into @temp_result values (@myLastString, @nr)
        set @myLastString=@myString
        set @nr=1
    end
    FETCH NEXT FROM string_cursor into @myString
END
insert into @temp_result values (@myLastString, @nr)
CLOSE string_cursor;
DEALLOCATE string_cursor;

select * from @temp_result

结果:

A   2
B   1
C   1
A   1
B   2

答案 2 :(得分:1)

试试这个:

;with sample as (
    select 'A' as columnx
    union all
    select 'A'
    union all
    select 'B'
    union all
    select 'C'
    union all
    select 'A'
    union all
    select 'B'
    union all
    select 'B'
), data 
as (
select columnx,
  Row_Number() over(order by (select 0)) id 
  from  sample
  ) , CTE as (

        select * , 
  Row_Number() over(order by (select 0)) rno from data

  ) , result as (

     SELECT  d.*
                , ( SELECT  MAX(ID)
                    FROM    CTE c
                    WHERE   NOT EXISTS (SELECT * FROM CTE
                                        WHERE rno = c.rno-1 and columnx = c.columnx)
                            AND c.ID <= d.ID) AS g
        FROM    data d
  )



SELECT columnx,
       COUNT(1) cnt
FROM   result
GROUP  BY columnx,
          g  

结果:

columnx cnt
A         2
B         1
C         1
A         1
B         2