[英]Summarize two columns that have a many-to-many relationship in an SQL database
I have the following database tables Transactions
and Payments
.我有以下数据库表
Transactions
和Payments
。 The data is structured as such that both Transactions and Payments have a many-to-many relationship, which are joined together in a query as such:数据的结构使得交易和付款都具有多对多关系,它们在查询中连接在一起,如下所示:
SELECT Transactions.Id, Payments.Id, Transactions.Amount
FROM Transactions
LEFT JOIN Payments ON Transactions.Id = Payments.TransactionId
| Transactions.Id | Payments.PaymentId | Transactions.Amount |
| ----------------| -------------------| --------------------|
| 3492 | 123456 | 123 |
| 3492 | 123457 | 123 |
| 3493 | 123458 | 300 |
| 3494 | 123459 | 10 |
| 3495 | 123459 | 25 |
I want to be able to simplify the table into something like below (if this is at all even possible in SQL)我希望能够将表简化为如下所示(如果这在 SQL 中是可能的)
| Transactions.Id | Payments.PaymentId | Transactions.Amount |
| ----------------| -------------------| --------------------|
| 3492 | 123456, 123457 | 123 |
| 3493 | 123458 | 300 |
| 3494, 3495 | 123459 | 35 |
...or even without the third column (if it reduces complexity) ...甚至没有第三列(如果它降低了复杂性)
| Transactions.Id | Payments.PaymentId |
| ----------------| -------------------|
| 3492 | 123456, 123457 |
| 3493 | 123458 |
| 3494, 3495 | 123459 |
What I have so far:到目前为止我所拥有的:
SELECT
Transactions.Id,
STUFF((SELECT '; ' + CAST(Payments.Id as varchar)
FROM Payments
WHERE Payments.TransactionId = Transactions.Id
FOR XML PATH('')), 1, 1, '') [PaymentIds]
FROM Transactions
| Transactions.Id | PaymentIds |
| ----------------| -------------------|
| 3492 | 123456, 123457 |
| 3493 | 123458 |
| 3494 | 123459 |
| 3495 | 123459 |
How do I add Transactions.Id into a comma separated list as well?如何将 Transactions.Id 添加到逗号分隔列表中? I am using SQL Server 12.0.2000.8
我正在使用 SQL 服务器 12.0.2000.8
Basically, you have to take two passes in order to aggregate the payments per transaction and then the transaction per payment aggregate.基本上,您必须通过两次才能汇总每笔交易的付款,然后汇总每笔付款的交易。 This assumes (based on the sample data and desired output) that when a payment applies to multiple transactions, you want the sum, but when a transaction has multiple payments, you want the max (or they'll always be the same in which case max works just fine?):
这假设(基于样本数据和所需的输出)当付款适用于多个交易时,您需要总和,但是当交易有多个付款时,您需要最大值(或者在这种情况下它们总是相同的max 工作正常吗?):
;WITH FirstPass AS
(
SELECT t.Id, pId = STUFF(
(SELECT ', ' + CONVERT(varchar(11), p.Id)
FROM dbo.Payments AS p
WHERE p.TransactionId = t.Id
ORDER BY p.Id
FOR XML PATH(''), TYPE).value(N'./text()[1]',
N'varchar(max)'), 1, 2, ''),
Amount = MAX(t.Amount)
FROM dbo.Transactions AS t
GROUP BY t.Id
)
SELECT [Transactions.Id] = STUFF(
(SELECT ', ' + CONVERT(varchar(11), fp.Id)
FROM FirstPass AS fp
WHERE fp.pId = FirstPass.pId
ORDER BY fp.pId
FOR XML PATH(''), TYPE).value(N'./text()[1]',
N'varchar(max)'), 1, 2, ''),
[Payments.PaymentId] = FirstPass.pId,
Amount = SUM(FirstPass.Amount)
FROM FirstPass
GROUP BY FirstPass.pId;
Output: Output:
Transactions.Id![]() |
Payments.PaymentId ![]() |
Amount![]() |
---|---|---|
3492 ![]() |
123456, 123457 ![]() |
123.00 ![]() |
3493 ![]() |
123458 ![]() |
300.00 ![]() |
3494, 3495 ![]() |
123459 ![]() |
35.00 ![]() |
On SQL Server 2017+ (or Azure SQL Database) this becomes much simpler, though still a little convoluted for this specific use case.在 SQL Server 2017+(或 Azure SQL 数据库)上,这变得更加简单,尽管对于这个特定的用例来说仍然有点复杂。 This doesn't help you right now, but could help other readers today, future readers, or even future you:
这对你现在没有帮助,但可以帮助今天的其他读者、未来的读者,甚至未来的你:
;WITH FirstPass AS
(
SELECT t.Id, ca.pId, Amount = MAX(t.Amount)
FROM dbo.Transactions AS t
CROSS APPLY
(
SELECT pId = STRING_AGG(p.Id, ', ')
FROM dbo.Payments AS p
WHERE p.TransactionId = t.Id
) AS ca GROUP BY t.Id, ca.pId
)
SELECT [Transactions.Id] = STRING_AGG(Id, ', '),
[Payments.PaymentId] = pId,
Amount = SUM(Amount)
FROM FirstPass
GROUP BY pId;
Same output:同 output:
The following code generates the output you want下面的代码生成你想要的output
WITH cte1 AS(
SELECT
Transactions.Id AS TransactionID,
Payments.Id AS PaymentID,
max(Transactions.amount) Amount
FROM Transactions
LEFT JOIN Payments ON Transactions.Id = Payments.TransactionId
GROUP BY Transactions.Id,Payments.Id),
cte2 AS(
SELECT
STUFF((SELECT ',' + cast(t2.TransactionID as varchar(100))
FROM cte1 t2
WHERE t2.PaymentID = t1.PaymentID
FOR XML PATH(''),TYPE).value('(./text())[1]','varchar(MAX)'),1,1,'')TransactionID,
STUFF((SELECT ',' + cast(t2.PaymentID as varchar(100))
FROM cte1 t2
WHERE t2.TransactionID = t1.TransactionID
FOR XML PATH(''),TYPE).value('(./text())[1]','varchar(MAX)'),1,1,'')PaymentID,
(SELECT sum(Amount)
FROM cte1 t2
WHERE t2.PaymentID = t1.PaymentID
GROUP BY PaymentID)Amount
FROM cte1 t1
)
SELECT TransactionID,PaymentID,Amount
FROM cte2
GROUP BY TransactionID,PaymentID,Amount
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.