我有以下示例数据:
Id Name Quantity
1 Red 1
2 Red 3
3 Blue 1
4 Red 1
5 Yellow 3
因此,对于此示例,总共有5个红色,1个蓝色和3个黄色。我正在寻找一种通过Color对它们进行分组的方法,但每组最多2个项目(排序并不重要)。像这样:
Name QuantityInPackage
Red 2
Red 2
Red 1
Blue 1
Yellow 2
Yellow 1
有关如何在MS-SQL 2005上使用T-SQL实现此目的的任何建议吗?
答案 0 :(得分:6)
我会定义一个包含序列号的表,比如1
到1000
并加入该表(除非您的数据库支持在查询中使用CONNECT BY
生成这些数字):< / p>
表号
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
答案 1 :(得分:1)
您需要使用数字表来取消数据的显示以生成多行:
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 :(得分: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
然后,在主查询中,首先对数据进行分组(求和),然后使用bucket函数:
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(只需更改参数)。
答案 3 :(得分:0)
这非常粗糙,但确实有效。
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