分组,拆分和计数行

时间:2011-02-21 16:38:15

标签: sql-server sql-server-2005 tsql

给出这个表和数据:

DECLARE @Table table (RowID int, RowCode char(1), RowValue int);set nocount on
INSERT @Table VALUES ( 6,'A',3757 )
INSERT @Table VALUES ( 5,'A',37827)
INSERT @Table VALUES (14,'A',48411)
INSERT @Table VALUES ( 1,'A',48386)
INSERT @Table VALUES (20,'A',48450)
INSERT @Table VALUES ( 7,'A',46155)
INSERT @Table VALUES (13,'A',721  )
INSERT @Table VALUES ( 2,'A',49335)
INSERT @Table VALUES (15,'A',4700 )
INSERT @Table VALUES (19,'A',64416)
INSERT @Table VALUES ( 8,'A',27246)
INSERT @Table VALUES (12,'B',54929)
INSERT @Table VALUES (16,'B',3872 )
INSERT @Table VALUES ( 3,'C',728  )
INSERT @Table VALUES (11,'C',1050 )
INSERT @Table VALUES ( 9,'C',3191 )
INSERT @Table VALUES (17,'C',866  )
INSERT @Table VALUES ( 4,'C',838  )
INSERT @Table VALUES (10,'D',550  )
INSERT @Table VALUES (18,'D',1434 );set nocount off

我需要这个:

                       VVVVVVVV
RowID RowCode RowValue RowChunk
----- ------- -------- --------
1     A       48386    1       
2     A       49335    1       
5     A       37827    1       
6     A       3757     1       
7     A       46155    1       
8     A       27246    2       
13    A       721      2       
14    A       48411    2       
15    A       4700     2       
19    A       64416    2       
20    A       48450    3       
12    B       54929    4       
16    B       3872     4       
3     C       728      5       
4     C       838      5       
9     C       3191     5       
11    C       1050     5       
17    C       866      5       
10    D       550      6       
18    D       1434     6    

RowChunk从1开始,每次RowCode更改时增加1和/或有5个相同的RowCode值。

4 个答案:

答案 0 :(得分:2)

基本上我的解决方案使用与您相同的方法,只使用稍微不同的设备。

WITH NumberedRows AS (
  SELECT
    RowID,
    RowCode,
    RowValue,
    CodeChunk = (ROW_NUMBER() OVER (PARTITION BY RowCode ORDER BY RowID) - 1) / 5
  FROM @Table
)
SELECT
  RowID,
  RowCode,
  RowValue,
  RowChunk = DENSE_RANK() OVER (ORDER BY RowCode, CodeChunk)
FROM NumberedRows

答案 1 :(得分:0)

我认为没有分析功能或任何合理的组合,这将解决这个问题。你必须用光标做RBAR,或者我的经验稍微快一点。

此循环示例假定RowID是唯一的。如果RowID不是集群PK,那么这将非常慢,所以如果是这种情况,你将需要创建一个临时表。

DECLARE @RowID         INT = (SELECT MIN(RowID) FROM @Table)
DECLARE @MaxRowID      INT = (SELECT MAX(RowID) FROM @Table)
DECLARE @RowCode       CHAR(1)
DECLARE @LastRowCode   CHAR(1)
DECLARE @RowValue      INT
DECLARE @Chunk         INT = 0
DECLARE @RecsThisChunk INT
DECLARE @Results       TABLE (RowID INT NOT NULL PRIMARY KEY, RowCode     CHAR(1) NOT NULL, RowValue INT NOT NULL, Chunk INT NOT NULL)

WHILE @RowID <= @MaxRowID
    BEGIN
    -- Handle gaps in RowID
    IF NOT EXISTS (SELECT * FROM @Table WHERE RowID = @RowID) GOTO EndOfLoop

    -- Load values for this record
    SELECT @RowCode = RowCode, @RowValue = RowValue FROM @Table WHERE RowID = @RowID

    IF @LastRowCode IS NULL OR @RowCode <> @LastRowCode OR @RecsThisChunk = 5
        BEGIN
        -- Start a new chunk
        SET @Chunk = @Chunk + 1
        SET @RecsThisChunk = 1
        END
    ELSE
        BEGIN
        -- Same chunk
        SET @RecsThisChunk = @RecsThisChunk + 1
        END

    SET @LastRowCode = @RowCode

    INSERT INTO @Results (RowID, RowCode, RowValue, Chunk) VALUES (@RowID, @RowCode, @RowValue, @Chunk)

    EndOfLoop:
    SET @RowID = @RowID + 1
    END

SELECT * FROM @Results

您可能会在2005年对此进行一些调整,我会定期使用2008并且不记得所有的小差异。

仅供参考,您显示的结果与样本数据不完全匹配。

希望这有帮助!我看到的唯一选择是游标,或在应用程序层中处理它。

答案 2 :(得分:0)

这是您正在寻找的答案:

create Table [table] (RowID int, RowCode char(1), RowValue int)
INSERT [Table] VALUES ( 6,'A',3757 ) 
INSERT [Table] VALUES ( 5,'A',37827) 
INSERT [Table] VALUES (14,'A',48411) 
INSERT [Table] VALUES ( 1,'A',48386) 
INSERT [Table] VALUES (20,'A',48450) 
INSERT [Table] VALUES ( 7,'A',46155) 
INSERT [Table] VALUES (13,'A',721  ) 
INSERT [Table] VALUES ( 2,'A',49335) 
INSERT [Table] VALUES (15,'A',4700 ) 
INSERT [Table] VALUES (19,'A',64416) 
INSERT [Table] VALUES ( 8,'A',27246) 
INSERT [Table] VALUES (12,'B',54929)
INSERT [Table] VALUES (16,'B',3872 )
INSERT [Table] VALUES ( 3,'C',728  ) 
INSERT [Table] VALUES (11,'C',1050 ) 
INSERT [Table] VALUES ( 9,'C',3191 ) 
INSERT [Table] VALUES (17,'C',866  ) 
INSERT [Table] VALUES ( 4,'C',838  ) 
INSERT [Table] VALUES (10,'D',550  ) 
INSERT [Table] VALUES (18,'D',1434 ) 


IF object_id('tempdb..#tempTable') IS NOT NULL
BEGIN
  DROP TABLE #tempTable
END

CREATE TABLE #tempTable
(RowID int, RowCode char(1), RowValue int,RowChunk int)

INSERT INTO #tempTable
select RowID,RowCode,RowValue,null from [table] 


declare @RowId int
declare @RowCode char(1)
declare @Count int
declare @CurrentCode char(1)
declare @CountCurrent int

set @Count=1
set @CurrentCode=1
set @CountCurrent=0


DECLARE contact_cursor CURSOR FOR
SELECT RowID,RowCode FROM [table]

OPEN contact_cursor
FETCH NEXT FROM contact_cursor into @RowId,@RowCode
set @CurrentCode=@RowCode
WHILE @@FETCH_STATUS = 0
BEGIN
  if(@CurrentCode=@RowCode)

  begin
    if(@CountCurrent=5)
    begin
      set @CountCurrent=1
      set @Count=@Count+1
      update #tempTable set RowChunk=@Count where RowID=@RowID
    end
    else
    begin
      set @CountCurrent=@CountCurrent+1
      update #tempTable set RowChunk=@Count where RowID=@RowID
    end
  end

  else
  begin
    set @CurrentCode=@RowCode
    set @CountCurrent=1
    set @Count=@Count+1
    update #tempTable set RowChunk=@Count where RowID=@RowID
  end

  FETCH NEXT FROM contact_cursor into @RowId,@RowCode
END
CLOSE contact_cursor
DEALLOCATE contact_cursor 

select * from #tempTable
GO

答案 3 :(得分:0)

这没有循环的技巧:

;WITH NumberedRows AS (   
SELECT 
r.RowID, r.RowCode, r.RowValue, CEILING(ROW_NUMBER() OVER(PARTITION BY r.RowCode ORDER BY r.RowCode,r.RowID)/5.0) AS CodeRowChunk
FROM @Table  r
)
, AllChunks AS (
SELECT r.*,ROW_NUMBER() OVER(ORDER BY RowCode,CodeRowChunk) AS ChunkRowNumber
FROM (SELECT DISTINCT 
      RowCode, CodeRowChunk 
      FROM NumberedRows) r
)
SELECT
a.RowID, RowCode, a.RowValue,
(SELECT ChunkRowNumber FROM AllChunks c WHERE c.RowCode=a.RowCode and c.CodeRowChunk=a.CodeRowChunk) AS RowChunk
FROM NumberedRows  a