[英]SQL Server - Sum based on another column, and combine with STUFF/XML PATH?
我不確定這是否令人難以置信,所以請提前道歉。
CREATE TABLE TestOrder
(
[OrderLineID] INT NOT NULL IDENTITY PRIMARY KEY,
[Item] NVARCHAR(30) NULL,
[OrderQty] INT NULL,
[Status1] INT NULL,
[Quantity_at_sts1] INT NULL,
[Status2] INT NULL,
[Quantity_at_sts2] INT NULL,
[Status3] INT NULL,
[Quantity_at_sts3] INT NULL,
[Status4] INT NULL,
[Quantity_at_sts4] INT NULL,
[Status5] INT NULL,
[Quantity_at_sts5] INT NULL,
[OrderRef] NVARCHAR(10) NULL
)
INSERT INTO TestOrder
values
('TSHIRT','1','100','1','0','0','0','0','0','0','0','0','Ord.1'),
('SOCKS','4','50','4','0','0','0','0','0','0','0','0','Ord.2'),
('SHIRT','5','10','1','50','2','0','0','0','0','0','0','Ord.3'),
('SHIRT','5','100','2','0','0','0','0','0','0','0','0','Ord.3'),
('SOCKS','10','10','4','50','2','0','0','0','0','0','0','Ord.4'),
('SOCKS','10','50','3','100','1','0','0','0','0','0','0','Ord.4')
。
| OrderLineID | Item | OrderQty | Status1 | Quantity_at_sts1 | Status2 | Quantity_at_sts2 | Status3 | Quantity_at_sts3 | Status4 | Quantity_at_sts_4 | Status5 | Quantity_at_sts5 | OrderRef |
|-------------|------|----------|---------|------------------|---------|------------------|---------|------------------|---------|-------------------|---------|------------------|----------|
| 1 |TSHIRT| 1 | 100 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Ord.1 |
| 2 |SOCKS | 4 | 50 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Ord.2 |
| 3 |SHIRT | 5 | 10 | 1 | 50 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | Ord.3 |
| 4 |SHIRT | 5 | 100 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Ord.3 |
| 5 |SOCKS | 10 | 10 | 4 | 50 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | Ord.4 |
| 6 |SOCKS | 10 | 50 | 3 | 100 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | Ord.4 |
所以這個表實際上是一個訂單表,所有“status1,quantity_at_sts1,status2 ......”等列實際上是該訂單的進度。 想象一下,你有10到100之間的各種狀態,10個'未開始',100個'完成和發送'。 “OrderRef”列實際上是這些感興趣的訂單的關鍵標識符; 例如,'Ord.3'和'Ord.4'的4行實際上只是每個訂單上的一個單項,但每行的狀態不同。
到目前為止,我一直在使用case語句將所有這些狀態放到一個更容易閱讀的列中(忽略所有的轉換,因為它們僅在實際數據上需要):
select
CASE
WHEN status2 = 0 THEN '['+CAST(status1 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts1 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10))
WHEN status2 > 0 AND status3 = 0 THEN '['+CAST(status1 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts1 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10))+' - '+'['+CAST(status2 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts2 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10))
WHEN status3 > 0 AND status4 = 0 THEN '['+CAST(status1 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts1 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10))+' - '+'['+CAST(status2 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts2 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10))+' - ['+CAST(status3 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts3 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10))
WHEN status4 > 0 AND status5 = 0 THEN '['+CAST(status1 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts1 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10))+' - '+'['+CAST(status2 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts2 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10))+' - ['+CAST(status3 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts3 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10)) + ' - ['+CAST(status4 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts4 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10))
when status5 > 0 then '['+CAST(status1 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts1 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10))+' - '+'['+CAST(status2 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts2 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10))+' - ['+CAST(status3 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts3 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10)) + ' - ['+CAST(status4 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts4 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10)) + ' - ['+CAST(status5 AS NVARCHAR(10))+'] '+CAST(CAST(CAST(quantity_at_sts5 AS DECIMAL(20, 6)) AS FLOAT) AS NVARCHAR(10))
END AS 'all_statuses'
, *
from testorder
。
| all_statuses | OrderLineID | Item | OrderQty | Status1 | Quantity_at_sts1 | Status2 | Quantity_at_sts2 | Status3 | Quantity_at_sts3 | Status4 | Quantity_at_sts_4 | Status5 | Quantity_at_sts5 | OrderRef |
|------------------|--------------|------|----------|---------|------------------|---------|------------------|---------|------------------|---------|-------------------|---------|------------------|----------|
| [100] 1 | 1 |TSHIRT| 1 | 100 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Ord.1 |
| [50] 4 | 2 |SOCKS | 4 | 50 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Ord.2 |
| [10] 1 - [50] 2 | 3 |SHIRT | 5 | 10 | 1 | 50 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | Ord.3 |
| [100] 2 | 4 |SHIRT | 5 | 100 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Ord.3 |
| [10] 4 - [50] 2 | 5 |SOCKS | 10 | 10 | 4 | 50 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | Ord.4 |
| [50] 3 - [100] 1 | 6 |SOCKS | 10 | 50 | 3 | 100 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | Ord.4 |
我的理想是按每個唯一的OrderRef值匯總,all_statuses是具有OrderRef值的所有行的總和量:
| all_statuses | OrderQty | OrderRef |
|----------------------------|------------|-----------|
| [100] 1 | 1 | Ord.1 |
| [50] 4 | 4 | Ord.2 |
| [10] 1 - [50] 2 - [100] 2 | 5 | Ord.3 |
| [10] 4 - [50] 5 - [100] 1 | 10 | Ord.4 |
但是我有兩個問題我正在努力:
我對STUFF FOR XML PATH有一點經驗,並認為我可以用STUFF組合做一些荒謬的CASE,但我很難找到一種方法。 這有點太復雜嗎?
第一步是將列拆分為行,您可以使用CROSS APPLY
和表值構造函數來執行
SELECT o.OrderRef, x.*
FROM #TestOrder AS o
CROSS APPLY
(VALUES
(1, o.Status1, o.Quantity_at_sts1),
(2, o.Status2, o.Quantity_at_sts2),
(3, o.Status3, o.Quantity_at_sts3),
(4, o.Status4, o.Quantity_at_sts4),
(5, o.Status5, o.Quantity_at_sts5)
) x (StatusNumber, StatusID, Quantity)
WHERE x.StatusID > 0;
這使:
OrderRef StatusNumber StatusID Quantity
--------------------------------------------------
Ord.1 1 100 1
Ord.2 1 50 4
Ord.3 1 10 1
Ord.3 2 50 2
Ord.3 1 100 2
Ord.4 1 10 4
Ord.4 2 50 2
Ord.4 1 50 3
Ord.4 2 100 1
然后,您需要總結按順序分組的數量,這是一個簡單的SUM
/ GROUP BY
。 我還添加了一個ROW_NUMBER()
列,以便在串聯期間訂購項目時使用:
SELECT o.OrderRef,
Quantity = SUM(x.Quantity),
x.StatusID,
RowNumber = ROW_NUMBER() OVER(PARTITION BY o.OrderRef ORDER BY MIN(o.OrderLineID), MIN(x.StatusNumber))
FROM #TestOrder AS o
CROSS APPLY
(VALUES
(1, o.Status1, o.Quantity_at_sts1),
(2, o.Status2, o.Quantity_at_sts2),
(3, o.Status3, o.Quantity_at_sts3),
(4, o.Status4, o.Quantity_at_sts4),
(5, o.Status5, o.Quantity_at_sts5)
) x (StatusNumber, StatusID, Quantity)
WHERE x.StatusID > 0
GROUP BY x.StatusID, o.OrderRef
OrderRef Quantity StatusID RowNumber
----------------------------------------------
Ord.1 1 100 1
Ord.2 4 50 1
Ord.3 1 10 1
Ord.3 2 50 2
Ord.3 2 100 3
Ord.4 4 10 1
Ord.4 5 50 2 <-- TWO ROWS GROUPED HERE
Ord.4 1 100 3
最后,您可以使用上面派生的表來創建字符串,然后使用SQL Server的XML擴展連接它們:
WITH ALLStatuses AS
( SELECT o.OrderRef,
Quantity = SUM(x.Quantity),
x.StatusID,
RowNumber = ROW_NUMBER() OVER(PARTITION BY o.OrderRef ORDER BY MIN(o.OrderLineID), MIN(x.StatusNumber))
FROM #TestOrder AS o
CROSS APPLY
(VALUES
(1, o.Status1, o.Quantity_at_sts1),
(2, o.Status2, o.Quantity_at_sts2),
(3, o.Status3, o.Quantity_at_sts3),
(4, o.Status4, o.Quantity_at_sts4),
(5, o.Status5, o.Quantity_at_sts5)
) x (StatusNumber, StatusID, Quantity)
WHERE x.StatusID > 0
GROUP BY x.StatusID, o.OrderRef
)
SELECT all_statuses = STUFF(( SELECT CONCAT(' - ', QUOTENAME(S.StatusID), ' ', s.Quantity)
FROM ALLStatuses AS s
WHERE s.OrderRef = o.OrderRef
ORDER BY RowNumber
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 3, ''),
o.OrderQty,
o.OrderRef
FROM #TestOrder AS o
GROUP BY o.OrderRef, o.OrderQty;
產量
all_statuses OrderQty OrderRef
------------------------------------------------
[100] 1 1 Ord.1
[50] 4 4 Ord.2
[10] 1 - [50] 2 - [100] 2 5 Ord.3
[10] 4 - [50] 5 - [100] 1 10 Ord.4
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.