4

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

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

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

我有一张表,其中有一列 ( columnx),其中的数据如下:

A
A
B
C
A
B
B

我想要的查询结果应该是这样的:

2 A
1 B
1 C
1 A
2 B

这在 sql 中是否可能,或者仅仅编写一个小 C# 应用程序来做到这一点会更容易吗?

4

3 回答 3

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)
;

您可以在 SQL Fiddle 上查看该方法。

如果sortcolumn是保证没有间隙的自增整数列,您可以将第一个ROW_NUMBER()表达式替换为 just sortcolumn。但是,我想,这一般不能保证。此外,您可能确实希望按时间戳而不是整数进行排序。

于 2012-04-05T05:14:40.453 回答
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
于 2012-04-04T09:34:43.843 回答
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
于 2012-04-04T10:31:57.887 回答