SQL按行计数的模分组

SQL按行计数的模分组,sql,tsql,group-by,Sql,Tsql,Group By,我有以下样本数据: 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

我有以下样本数据:

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实现这一点,您有什么建议吗?

我会定义一个包含序号的表,比如1到1000,然后连接该表,除非您的数据库支持在查询中生成这些数字,如Oracle使用CONNECT BY:

表编号

我使用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

您需要使用数字表取消填充数据以生成多行:

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

这里的难点不是分组或模/除,而是你需要做一个聚合和,然后再次分解数据。实际上没有任何红色的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

这应该适用于任何铲斗大小,不必是2,只要更改参数即可。

这非常粗糙,但它可以工作

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

什么版本的SQL Server或Informix?恩特尔并不是你想要的…你如何从第一盘打到第二盘?如果你分组,那么每种颜色只有一行。拉杰·莫尔:这正是我的问题。包装中的数量最多为2个。所以它可以是1或2。如果一种颜色有两个以上的项目,那么它需要显示在下一行。您如何确定QuantityInPackage?PackageID在哪里?这看起来是最好用代码处理的问题之一。这是一种选择吗?
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
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