группировка, разбиение и подсчет строк - PullRequest
1 голос
/ 21 февраля 2011

с учетом этой таблицы и данных:

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 и увеличивается на 1 для каждого изменения RowCode и / или когда естьбыло 5 одинаковых значений RowCode.

Ответы [ 4 ]

2 голосов
/ 21 февраля 2011

В основном, мое решение использует тот же подход, что и ваш, только с немного другими устройствами.

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
0 голосов
/ 21 февраля 2011

Это ответ, который вы ищете:

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
0 голосов
/ 21 февраля 2011

это делает трюк без цикла:

;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
0 голосов
/ 21 февраля 2011

Я не думаю, что есть аналитическая функция или какая-либо разумная комбинация таких, которая решит эту проблему. Вы должны будете сделать это 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 и не помню всех небольших различий.

К вашему сведению, результаты, которые вы показываете, не совсем соответствуют образцам данных.

Надеюсь, это поможет! Единственная альтернатива, которую я вижу, это курсор или обработка этого на уровне приложения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...