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