【问题标题】:SQL Group By Modulo of Row CountSQL Group By Modulo of Row Count
【发布时间】:2011-02-03 10:21:31
【问题描述】:

我有以下示例数据:

Id     Name     Quantity
1      Red      1
2      Red      3
3      Blue     1
4      Red      1
5      Yellow   3

所以对于这个例子,总共有 5 个红色、1 个蓝色和 3 个黄色。我正在寻找一种按颜色对它们进行分组的方法,但每组最多包含 2 个项目(排序并不重要)。像这样:

Name     QuantityInPackage
Red      2
Red      2
Red      1
Blue     1
Yellow   2
Yellow   1

关于如何在 MS-SQL 2005 上使用 T-SQL 完成此任务的任何建议?

【问题讨论】:

  • 什么版本的 SQL Server 或 Informix? NTILE 不是你想要的……
  • 如何从第一组到第二组?如果您GROUP BY,那么每种颜色将只有一行。
  • Raj More:正是我的问题。 Package 中的数量最多为 2。因此它可以是 1 或 2。如果“颜色”的项目超过 2 个,则需要在下一行显示。
  • 如何确定QuantityInPackage? PackageID 在哪里?
  • 这看起来像是最好在代码中处理的问题之一。这是一个选择吗?

标签: sql tsql group-by


【解决方案1】:

我将定义一个包含序列号的表,例如 11000 并加入该表(除非您的数据库支持在查询中生成这些数字,例如 Oracle 使用 CONNECT BY):

表格编号

n
1
2
3
...

我使用 Oracle 尝试了以下查询(也应该使用 TSQL):

With summed_colors As (
  Select name, Sum(quantity) quantity
  From colors
  Group By name
)
Select
  name,
  Case When n*2-1 = quantity Then 1 Else 2 End quantityInPackage
From summed_colors
Join nums On ( n*2-1 <= quantity )
Order By name, quantityInPackage Desc

然后它返回

Blue   1
Red    2
Red    2
Red    1
Yellow 2
Yellow 1

【讨论】:

    【解决方案2】:

    您需要使用数字表来反透视数据以生成多行:

    DECLARE @PackageSize AS int
    SET @PackageSize = 2
    
    DECLARE @numbers AS TABLE (Number int)
    INSERT  INTO @numbers
    VALUES  (1)
    INSERT  INTO @numbers
    VALUES  (2)
    INSERT  INTO @numbers
    VALUES  (3)
    INSERT  INTO @numbers
    VALUES  (4)
    INSERT  INTO @numbers
    VALUES  (5)
    INSERT  INTO @numbers
    VALUES  (6)
    INSERT  INTO @numbers
    VALUES  (7)
    INSERT  INTO @numbers
    VALUES  (8)
    INSERT  INTO @numbers
    VALUES  (9)
    INSERT  INTO @numbers
    VALUES  (10)
    
    DECLARE @t AS TABLE
        (
         Id int
        ,Nm varchar(6)
        ,Qty int
        )
    INSERT  INTO @t
    VALUES  (1, 'Red', 1)
    INSERT  INTO @t
    VALUES  (2, 'Red', 3)
    INSERT  INTO @t
    VALUES  (3, 'Blue', 1)
    INSERT  INTO @t
    VALUES  (4, 'Red', 1)
    INSERT  INTO @t
    VALUES  (5, 'Yellow', 3) ;
    WITH    Totals
              AS (
                  SELECT    Nm
                           ,SUM(Qty) AS TotalQty
                           ,SUM(Qty) / @PackageSize AS NumCompletePackages
                           ,SUM(Qty) % @PackageSize AS PartialPackage
                  FROM      @t
                  GROUP BY  Nm
                 )
        SELECT  Totals.Nm
               ,@PackageSize AS QuantityInPackage
        FROM    Totals
        INNER JOIN @numbers AS numbers
                ON numbers.Number <= Totals.NumCompletePackages
        UNION ALL            
        SELECT  Totals.Nm
               ,PartialPackage AS QuantityInPackage
        FROM    Totals
        WHERE PartialPackage <> 0
    

    【讨论】:

      【解决方案3】:

      这里的难点不是分组或模/除,而是您需要进行聚合(求和)然后再次分解数据。实际上没有任何“红色 2”行,您必须以某种方式创建它们。

      对于 SQL Server 2005+,我可能会使用一个函数来“爆炸”:

      CREATE FUNCTION dbo.CreateBuckets
      (
          @Num int,
          @MaxPerGroup int
      )
      RETURNS TABLE
      AS RETURN
      WITH First_CTE AS
      (
          SELECT CASE
              WHEN @MaxPerGroup < @Num THEN @MaxPerGroup
              ELSE @Num
          END AS Seed
      ),
      Sequence_CTE AS
      (
          SELECT Seed AS [Current], Seed AS Total
          FROM First_CTE
      
          UNION ALL
      
          SELECT
              CASE
                  WHEN (Total + @MaxPerGroup) > @Num THEN (@Num - Total)
                  ELSE @MaxPerGroup
              END,
              Total + @MaxPerGroup
          FROM Sequence_CTE
          WHERE Total < @Num
      )
      SELECT [Current] AS Num
      FROM Sequence_CTE
      

      然后,在主查询中,先对数据进行分组(求和),然后使用存储桶功能:

      WITH Totals AS
      (
          SELECT Name, SUM(Quantity) AS Total
          FROM Table
          GROUP BY Name
      )
      SELECT Name, b.Num AS QuantityInPackage
      FROM Totals
      CROSS APPLY dbo.CreateBuckets(Total, 2) b
      

      这应该适用于任何桶大小,不必为 2(只需更改参数)。

      【讨论】:

        【解决方案4】:

        这很粗略,但确实有效。

        CREATE TABLE #Colors
            (
            Id int,
            Name varchar(50),
            Quantity int
            )
        
        INSERT INTO #Colors VALUES (1, 'Red', 1)
        INSERT INTO #Colors VALUES (2, 'Red', 3)
        INSERT INTO #Colors VALUES (3, 'Blue', 1)
        INSERT INTO #Colors VALUES (4, 'Red', 1)
        INSERT INTO #Colors VALUES (5, 'Yellow', 3)
        INSERT INTO #Colors VALUES (6, 'Green', 2)
        
        SELECT
            Name,
            SUM(Quantity) AS TotalQuantity
        INTO #Summed
        FROM
            #Colors
        GROUP BY
            Name
        
        SELECT
            Name,
            TotalQuantity / 2 AS RecordsWithQuantity2,
            TotalQuantity % 2 AS RecordsWithQuantity1
        INTO #SortOfPivot
        FROM
            #Summed
        ORDER BY
            Name
        
        DECLARE @RowCount int
        SET @RowCount = (SELECT COUNT(*) FROM #SortOfPivot)
        DECLARE @Name varchar(50)
        DECLARE @TwosInsertCount int
        DECLARE @OnesInsertCount int
        
        CREATE TABLE #Result (Name varchar(50), Quantity int)
        
        WHILE @RowCount > 0
        BEGIN
            SET @Name = (SELECT TOP 1 Name FROM #SortOfPivot)
            SET @TwosInsertCount = (SELECT TOP 1 RecordsWithQuantity2 FROM #SortOfPivot)
            SET @OnesInsertCount = (SELECT TOP 1 RecordsWithQuantity1 FROM #SortOfPivot)
            WHILE @TwosInsertCount > 0
            BEGIN
                INSERT INTO #Result (Name, Quantity) VALUES (@Name, 2)
                SET @TwosInsertCount = @TwosInsertCount - 1
            END
            WHILE @OnesInsertCount > 0
            BEGIN
                INSERT INTO #Result (Name, Quantity) VALUES (@Name, 1)
                SET @OnesInsertCount =  @OnesInsertCount - 1
            END
            DELETE FROM #SortOfPivot WHERE Name = @Name
            SET @RowCount = (SELECT COUNT(*) FROM #SortOfPivot)
        END
        
        SELECT * FROM #Result
        DROP TABLE #Colors
        DROP TABLE #Result
        DROP TABLE #Summed
        DROP TABLE #SortOfPivot
        

        【讨论】:

          猜你喜欢
          • 2017-07-17
          • 1970-01-01
          • 2021-12-15
          • 1970-01-01
          • 2019-12-22
          • 2012-07-09
          • 1970-01-01
          • 2021-04-01
          • 2012-07-18
          相关资源
          最近更新 更多