如何解决“Stuff and 'For Xml Path'” 或 UNION 以排除重复行
这是问题的进一步进展:how to use "Stuff and 'For Xml Path'" to unite rows in table
我有 3 个表 - 发票、头寸和帐户,它们通过 SELECT 构建通用表,如下面的结果所示。我需要排除由于相同发票的不同帐户而出现的重复行。我认为它可以通过“Stuff and 'For Xml Path'”和/或 UNION 来解决,但我真的不知道该怎么做。
请协助解决此问题。提前致谢。
这是包含 DL 和样本数据群的 dbfiddle:https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=6401c2886a24b21239dade27e8c549ec
使用基于 SQL Server 2016 的 DevExpress 仪表板设计器。
查询:
-- DDL and sample data population,start
CREATE TABLE invoices
(
invoice VARCHAR(20) NOT NULL,id INT NOT NULL,);
INSERT invoices(invoice,id)
VALUES ('ty20210110',1);
INSERT invoices(invoice,id)
VALUES ('ty20210111',2);
INSERT invoices(invoice,id)
VALUES ('ty20210112',3);
CREATE TABLE positions
(
position VARCHAR(20) NOT NULL,quantity INT NOT NULL,price INT NOT NULL,summ INT NOT NULL,invoice INT NOT NULL,);
INSERT positions(position,quantity,price,summ,invoice)
VALUES ('p1000001',2,100,200,1);
INSERT positions(position,invoice)
VALUES ('p1000002',3,300,2);
INSERT positions(position,invoice)
VALUES ('p1000003',1,250,invoice)
VALUES ('p1000004',120,240,invoice)
VALUES ('p1000005',4,400,invoice)
VALUES ('p1000006',1001);
INSERT positions(position,invoice)
VALUES ('p1000007',5,80,3);
INSERT positions(position,invoice)
VALUES ('p1000008',500,3);
CREATE TABLE accounts
(
account INT NOT NULL,);
INSERT accounts(account,invoice)
VALUES (01,2);
INSERT accounts(account,invoice)
VALUES (02,invoice)
VALUES (03,1);
INSERT accounts(account,invoice)
VALUES (04,3);
INSERT accounts(account,invoice)
VALUES (05,invoice)
VALUES (06,3);
-- DDL and sample data population,end
SELECT
positions.position,positions.quantity,positions.price,positions.summ,invoices.invoice,accounts.account
FROM
positions
INNER JOIN
invoices invoices ON invoices.id = positions.invoice
INNER JOIN
accounts accounts ON invoices.id = accounts.invoice
结果:
位置 | 数量 | 价格 | 总和 | 发票 | 帐号 |
---|---|---|---|---|---|
p1000001 | 2 | 100 | 200 | in20210110 | 3 |
p1000001 | 2 | 100 | 200 | in20210110 | 5 |
p1000002 | 3 | 100 | 300 | in20210111 | 1 |
p1000002 | 3 | 100 | 300 | in20210111 | 2 |
p1000003 | 1 | 250 | 250 | in20210111 | 1 |
p1000003 | 1 | 250 | 250 | in20210111 | 2 |
p1000004 | 2 | 120 | 240 | in20210110 | 3 |
p1000004 | 2 | 120 | 240 | in20210110 | 5 |
p1000005 | 4 | 100 | 400 | in20210110 | 3 |
p1000005 | 4 | 100 | 400 | in20210110 | 5 |
p1000006 | 3 | 100 | 300 | in20210110 | 3 |
p1000006 | 3 | 100 | 300 | in20210110 | 5 |
p1000007 | 5 | 80 | 400 | in20210112 | 4 |
p1000007 | 5 | 80 | 400 | in20210112 | 6 |
p1000008 | 5 | 100 | 500 | in20210112 | 4 |
p1000008 | 5 | 100 | 500 | in20210112 | 6 |
要求的结果 1:
位置 | 数量 | 价格 | 总结 | 发票 | 帐号 |
---|---|---|---|---|---|
p1000001 | 2 | 100 | 200 | in20210110 | 3、5 |
p1000004 | 2 | 120 | 240 | in20210110 | 3、5 |
p1000005 | 4 | 100 | 400 | in20210110 | 3、5 |
p1000006 | 3 | 100 | 300 | in20210110 | 3、5 |
p1000002 | 3 | 100 | 300 | in20210111 | 1、2 |
p1000003 | 1 | 250 | 250 | in20210111 | 1、2 |
p1000007 | 5 | 80 | 400 | in20210112 | 4、6 |
p1000008 | 5 | 100 | 500 | in20210112 | 4、6 |
要求的结果 2:
位置 | 数量 | 价格 | 总和 | 发票 | 帐号 1 | 帐号 2 |
---|---|---|---|---|---|---|
p1000001 | 2 | 100 | 200 | in20210110 | 3 | 5 |
p1000004 | 2 | 120 | 240 | in20210110 | 3 | 5 |
p1000005 | 4 | 100 | 400 | in20210110 | 3 | 5 |
p1000006 | 3 | 100 | 300 | in20210110 | 3 | 5 |
p1000002 | 3 | 100 | 300 | in20210111 | 1 | 2 |
p1000003 | 1 | 250 | 250 | in20210111 | 1 | 2 |
p1000007 | 5 | 80 | 400 | in20210112 | 4 | 6 |
p1000008 | 5 | 100 | 500 | in20210112 | 4 | 6 |
解决方法
您的第一个结果集可以通过两种方式处理,具体取决于您的 SQL Server 版本。在 SSMS 中尝试以下示例:
创建数据
DECLARE @invoices table (
invoice VARCHAR(20) NOT NULL,id INT NOT NULL
);
INSERT INTO @invoices (invoice,id) VALUES
( 'ty20210110',1 ),( 'ty20210111',2 ),( 'ty20210112',3 );
DECLARE @positions table (
position VARCHAR(20) NOT NULL,quantity INT NOT NULL,price INT NOT NULL,summ INT NOT NULL,invoice INT NOT NULL
);
INSERT INTO @positions ( position,quantity,price,summ,invoice ) VALUES
( 'p1000001',2,100,200,( 'p1000002',3,300,( 'p1000003',1,250,( 'p1000004',120,240,( 'p1000005',4,400,( 'p1000006',( 'p1000007',5,80,3 ),( 'p1000008',500,3 );
DECLARE @accounts table (
account INT NOT NULL,invoice INT NOT NULL
);
INSERT INTO @accounts ( account,invoice ) VALUES
( 1,( 2,( 3,( 4,( 5,( 6,3 );
如果您使用的是 SQL Server 2017+
SELECT
positions.position,positions.quantity,positions.price,positions.summ,invoices.invoice,STRING_AGG ( accounts.account,',' ) AS account
FROM @positions positions
INNER JOIN @invoices invoices
ON invoices.id = positions.invoice
INNER JOIN @accounts accounts
ON invoices.id = accounts.invoice
GROUP BY
position,invoices.invoice
ORDER BY
invoice;
对于 Pre-SQL Server 2017
SELECT
positions.position,acct.account
FROM @positions positions
INNER JOIN @invoices invoices
ON invoices.id = positions.invoice
INNER JOIN @accounts accounts
ON invoices.id = accounts.invoice
OUTER APPLY (
SELECT STUFF ( (
SELECT ',' + CAST ( a.account AS varchar(50) ) AS "text()"
FROM @accounts a
WHERE
a.invoice = invoices.id
FOR XML PATH ( '' )
),'' ) AS account
) AS acct
GROUP BY
position,acct.account
ORDER BY
invoice;
两个查询都返回
+----------+----------+-------+------+------------+---------+
| position | quantity | price | summ | invoice | account |
+----------+----------+-------+------+------------+---------+
| p1000001 | 2 | 100 | 200 | ty20210110 | 3,5 |
| p1000004 | 2 | 120 | 240 | ty20210110 | 3,5 |
| p1000005 | 4 | 100 | 400 | ty20210110 | 3,5 |
| p1000006 | 3 | 100 | 300 | ty20210110 | 3,5 |
| p1000002 | 3 | 100 | 300 | ty20210111 | 1,2 |
| p1000003 | 1 | 250 | 250 | ty20210111 | 1,2 |
| p1000007 | 5 | 80 | 400 | ty20210112 | 4,6 |
| p1000008 | 5 | 100 | 500 | ty20210112 | 4,6 |
+----------+----------+-------+------+------------+---------+
您请求的第二个结果集变得相当复杂,并且需要使用 XML 数据类型。以下示例对您的数据进行了自由假设,最明显的是只需要两个帐户。话虽如此,您可以根据需要扩展 [account n]
中的 PIVOT
列,而不必求助于动态 SQL。
SELECT DISTINCT
positions.position,x.*
FROM @positions positions
INNER JOIN @invoices invoices
ON invoices.id = positions.invoice
INNER JOIN @accounts accounts
ON invoices.id = accounts.invoice
OUTER APPLY (
-- Create an XML account list --
SELECT CAST ( (
SELECT
'account ' + CAST ( ROW_NUMBER() OVER ( ORDER BY a.invoice ) AS varchar(50) ) AS id,a.account
FROM @accounts a
WHERE
a.invoice = invoices.id
FOR XML PATH ( 'data' ),ROOT ( 'accounts' )
) AS xml ) AS account_xml
) AS acct
OUTER APPLY (
-- PIVOT the account details --
SELECT
*
FROM (
SELECT
x.f.value( 'id[1]','varchar(50)' ) AS id,x.f.value( 'account[1]','varchar(50)' ) AS act
FROM acct.account_xml.nodes( '//accounts/data' ) x(f)
) AS d
PIVOT (
MAX ( act ) FOR id IN ( [account 1],[account 2] )
) AS p
) AS x
ORDER BY
invoice;
退货
+----------+----------+-------+------+------------+-----------+-----------+
| position | quantity | price | summ | invoice | account 1 | account 2 |
+----------+----------+-------+------+------------+-----------+-----------+
| p1000001 | 2 | 100 | 200 | ty20210110 | 3 | 5 |
| p1000004 | 2 | 120 | 240 | ty20210110 | 3 | 5 |
| p1000005 | 4 | 100 | 400 | ty20210110 | 3 | 5 |
| p1000006 | 3 | 100 | 300 | ty20210110 | 3 | 5 |
| p1000002 | 3 | 100 | 300 | ty20210111 | 1 | 2 |
| p1000003 | 1 | 250 | 250 | ty20210111 | 1 | 2 |
| p1000007 | 5 | 80 | 400 | ty20210112 | 4 | 6 |
| p1000008 | 5 | 100 | 500 | ty20210112 | 4 | 6 |
+----------+----------+-------+------+------------+-----------+-----------+
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。