我有一个使用WITH ROLLUP
编写的查询效果很好的查询。它是6列宽,最后一列包含表示订单金额的数字。其他5列中的每一列在识别该订单时逐渐更加具体,第5列是订单号。
查询显示我们组织中任何一个感兴趣的“级别”的所有总计。但是,我要求从报告中删除重复数据。没有重复的行,但是每个更通用的列在连续的行中都有很多重复的数据。
查询可以很好地生成如下结果:
+-----------------------------------------------------------------------------------------------+
¦ Affiliate Company ¦ Affiliate Name ¦ Customer Company ¦ Customer ¦ Order Number ¦ Total Sales ¦
¦-------------------+----------------+------------------+----------+--------------+-------------¦
¦ OL ¦ Brian ¦ Customer ¦ Dennis ¦ 105773 ¦ $111.60 ¦
¦ OL ¦ Brian ¦ Customer ¦ Steve ¦ 105776 ¦ $398.75 ¦
¦ OL ¦ Brian ¦ Customer ¦ NULL ¦ subtotal ¦ $510.35 ¦
¦ OL ¦ Brian ¦ NULL ¦ NULL ¦ subtotal ¦ $510.35 ¦
¦ OL ¦ NULL ¦ NULL ¦ NULL ¦ subtotal ¦ $510.35 ¦
¦ ght ¦ Tom ¦ Customer ¦ John ¦ 104686 ¦ $1,228.10 ¦
¦ ght ¦ Tom ¦ Customer ¦ Julie ¦ 105701 ¦ $152.64 ¦
¦ ght ¦ Tom ¦ Customer ¦ Jennifer ¦ 104681 ¦ $5.00 ¦
¦ ght ¦ Tom ¦ Customer ¦ Jennifer ¦ 105766 ¦ $218.79 ¦
¦ ght ¦ Tom ¦ Customer ¦ Jason ¦ 104684 ¦ $2,500.00 ¦
¦ ght ¦ Tom ¦ Customer ¦ Jason ¦ 104691 ¦ $321.28 ¦
¦ ght ¦ Tom ¦ Customer ¦ Jason ¦ 105744 ¦ $739.80 ¦
¦ ght ¦ Tom ¦ Customer ¦ Jean ¦ 104682 ¦ $3,990.00 ¦
¦ ght ¦ Tom ¦ Customer ¦ Random ¦ 104688 ¦ $1,328.40 ¦
¦ ght ¦ Tom ¦ Customer ¦ Random ¦ 105699 ¦ $5,112.00 ¦
¦ ght ¦ Tom ¦ Customer ¦ Random ¦ 105711 ¦ $219.10 ¦
¦ ght ¦ Tom ¦ Customer ¦ Random ¦ 105758 ¦ $2,202.50 ¦
¦ ght ¦ Tom ¦ Customer ¦ Jason ¦ 105739 ¦ $2,278.04 ¦
¦ ght ¦ Tom ¦ Customer ¦ Jason ¦ 105769 ¦ $820.84 ¦
¦ ght ¦ Tom ¦ Customer ¦ Jason ¦ 105770 ¦ $797.12 ¦
¦ ght ¦ Tom ¦ Customer ¦ Dee Dee ¦ 105702 ¦ $2,244.30 ¦
¦ ght ¦ Tom ¦ Customer ¦ NULL ¦ subtotal ¦ $24,157.91 ¦
¦ ght ¦ Tom ¦ NULL ¦ NULL ¦ subtotal ¦ $24,157.91 ¦
¦ ght ¦ NULL ¦ NULL ¦ NULL ¦ subtotal ¦ $24,157.91 ¦
¦ NULL ¦ NULL ¦ NULL ¦ NULL ¦ subtotal ¦ $24,668.26 ¦
+-----------------------------------------------------------------------------------------------+
但是,当我在混合中添加LAG以删除重复数据时,我得到了这个:
+----------------------------------------------------------------------------------------------------------+
¦ Affiliate Company ¦ Affiliate Name ¦ Customer Company ¦ Customer ¦ Order Number ¦ Total Sales ¦ Previous ¦
¦-------------------+----------------+------------------+----------+--------------+-------------+----------¦
¦ NULL ¦ NULL ¦ NULL ¦ NULL ¦ subtotal ¦ $24,668.26 ¦ NULL ¦
¦ OL ¦ NULL ¦ NULL ¦ NULL ¦ subtotal ¦ $510.35 ¦ NULL ¦
¦ OL ¦ Brian ¦ NULL ¦ NULL ¦ subtotal ¦ $510.35 ¦ NULL ¦
¦ OL ¦ Brian ¦ Customer ¦ NULL ¦ subtotal ¦ $510.35 ¦ NULL ¦
¦ OL ¦ Brian ¦ Customer ¦ Dennis ¦ 105773 ¦ $111.60 ¦ NULL ¦
¦ OL ¦ Brian ¦ Customer ¦ Steve ¦ 105776 ¦ $398.75 ¦ Dennis ¦
¦ ght ¦ NULL ¦ NULL ¦ NULL ¦ subtotal ¦ $24,157.91 ¦ Steve ¦
¦ ght ¦ Tom ¦ NULL ¦ NULL ¦ subtotal ¦ $24,157.91 ¦ NULL ¦
¦ ght ¦ Tom ¦ Customer ¦ NULL ¦ subtotal ¦ $24,157.91 ¦ NULL ¦
¦ ght ¦ Tom ¦ Customer ¦ John ¦ 104686 ¦ $1,228.10 ¦ NULL ¦
¦ ght ¦ Tom ¦ Customer ¦ Julie ¦ 105701 ¦ $152.64 ¦ John ¦
¦ ght ¦ Tom ¦ Customer ¦ Jennifer ¦ 104681 ¦ $5.00 ¦ Julie ¦
¦ ght ¦ Tom ¦ Customer ¦ Jennifer ¦ 105766 ¦ $218.79 ¦ Jennifer ¦
¦ ght ¦ Tom ¦ Customer ¦ Jason ¦ 104684 ¦ $2,500.00 ¦ Jennifer ¦
¦ ght ¦ Tom ¦ Customer ¦ Jason ¦ 104691 ¦ $321.28 ¦ Jason ¦
¦ ght ¦ Tom ¦ Customer ¦ Jason ¦ 105744 ¦ $739.80 ¦ Jason ¦
¦ ght ¦ Tom ¦ Customer ¦ Jean ¦ 104682 ¦ $3,990.00 ¦ Jason ¦
¦ ght ¦ Tom ¦ Customer ¦ Random ¦ 104688 ¦ $1,328.40 ¦ Jean ¦
¦ ght ¦ Tom ¦ Customer ¦ Random ¦ 105699 ¦ $5,112.00 ¦ Random ¦
¦ ght ¦ Tom ¦ Customer ¦ Random ¦ 105711 ¦ $219.10 ¦ Random ¦
¦ ght ¦ Tom ¦ Customer ¦ Random ¦ 105758 ¦ $2,202.50 ¦ Random ¦
¦ ght ¦ Tom ¦ Customer ¦ Jason ¦ 105739 ¦ $2,278.04 ¦ Random ¦
¦ ght ¦ Tom ¦ Customer ¦ Jason ¦ 105769 ¦ $820.84 ¦ Jason ¦
¦ ght ¦ Tom ¦ Customer ¦ Jason ¦ 105770 ¦ $797.12 ¦ Jason ¦
¦ ght ¦ Tom ¦ Customer ¦ Dee Dee ¦ 105702 ¦ $2,244.30 ¦ Jason ¦
+----------------------------------------------------------------------------------------------------------+
你可以看到我所做的只是添加“上一页”列,我的数据现在已经颠倒了。我的意图是我会回去过滤掉所有连续的副本。但是,如果数据向后反转,我无法有效地删除重复项,甚至也无法轻松读取结果。关于如何完成我想做的事情的任何想法?
我的代码如下:
更新:在排序帮助下,所有内容都使用以下代码:
WITH Names AS (
SELECT
Customer.CustomerID
, Customer.LastName + ', ' + Customer.FirstName + ' (' + Customer.Email + ')' AS 'Customer'
FROM
Customer
)
SELECT
CASE WHEN (Affiliate.Company = LAG(Affiliate.Company, 1) OVER (ORDER BY Affiliate.Company) AND GROUPING(Affiliate.Name) < 1) THEN NULL ELSE CASE WHEN GROUPING(Affiliate.Name) < 1 THEN Affiliate.Company ELSE Affiliate.Company + ' subtotal:' END END AS 'Affiliate Company'
, CASE WHEN (Affiliate.Name = LAG(Affiliate.Name, 1) OVER (ORDER BY Affiliate.Company, Affiliate.Name) AND GROUPING(CustomerLevel.Name) < 1) THEN NULL ELSE CASE WHEN GROUPING(CustomerLevel.Name) < 1 THEN Affiliate.Name ELSE Affiliate.Name + ' subtotal:' END END AS 'Affiliate Name'
, CASE WHEN (CustomerLevel.Name = LAG(CustomerLevel.Name, 1) OVER (ORDER BY Affiliate.Company, Affiliate.Name, CustomerLevel.Name) AND GROUPING(Names.Customer) < 1) THEN NULL ELSE CASE WHEN GROUPING(Names.Customer) < 1 THEN CustomerLevel.Name ELSE CustomerLevel.Name + ' subtotal:' END END AS 'Customer Company'
, Names.Customer AS 'Customer'
, CASE GROUPING(Orders.OrderNumber) WHEN 1 THEN CASE WHEN GROUPING(Affiliate.Company) = 1 THEN 'GRAND TOTAL' ELSE 'subtotal' END ELSE CONVERT(VARCHAR,Orders.OrderNumber) END AS 'Order Number'
, '$' + CONVERT(VARCHAR,CONVERT(MONEY,SUM(Orders.OrderSubtotal)),1) AS 'Total Sales'
FROM Orders INNER JOIN
Affiliate ON Orders.AffiliateID = Affiliate.AffiliateID INNER JOIN
Customer ON Orders.CustomerID = Customer.CustomerID INNER JOIN
CustomerLevel ON Customer.CustomerLevelID = CustomerLevel.CustomerLevelID INNER JOIN
Names ON Customer.CustomerID = Names.CustomerID
GROUP BY
Affiliate.Company
, Affiliate.Name
, CustomerLevel.Name
, Names.Customer
, Orders.OrderNumber
WITH ROLLUP
HAVING
GROUPING(Orders.OrderNumber) < 1
OR
GROUPING(Names.Customer) = 1
OR
GROUPING(Affiliate.Company) = 1
OR
GROUPING(Affiliate.Name) = 1
OR
GROUPING(CustomerLevel.Name) = 1
ORDER BY
CASE WHEN Affiliate.Company IS NULL THEN 1 ELSE 0 END
, Affiliate.Company
, CASE WHEN Affiliate.Name IS NULL THEN 1 ELSE 0 END
, Affiliate.Name
, CASE WHEN CustomerLevel.Name IS NULL THEN 1 ELSE 0 END
, CustomerLevel.Name
, CASE WHEN Names.Customer IS NULL THEN 1 ELSE 0 END
, Names.Customer
更新:如果有人有兴趣,这里是删除所有不必要的连续重复的结果:
+-------------------+-----------------+--------------------+----------+--------------+-------------+
| Affiliate Company | Affiliate Name | Customer Company | Customer | Order Number | Total Sales |
+-------------------+-----------------+--------------------+----------+--------------+-------------+
| OL | Brian | Customer | Dennis | 105773 | $111.60 |
| NULL | NULL | NULL | Steve | 105776 | $398.75 |
| NULL | NULL | Customer subtotal: | NULL | subtotal | $510.35 |
| NULL | Brian subtotal: | NULL | NULL | subtotal | $510.35 |
| WYN-OL subtotal: | NULL | NULL | NULL | subtotal | $510.35 |
| ght | Tom | Customer | John | 104686 | $1,228.10 |
| NULL | NULL | NULL | Julie | 105701 | $152.64 |
| NULL | NULL | NULL | Jennifer | 104681 | $5.00 |
| NULL | NULL | NULL | Jennifer | 105766 | $218.79 |
| NULL | NULL | NULL | Jason | 104684 | $2,500.00 |
| NULL | NULL | NULL | Jason | 104691 | $321.28 |
| NULL | NULL | NULL | Jason | 105744 | $739.80 |
| NULL | NULL | NULL | Jean | 104682 | $3,990.00 |
| NULL | NULL | NULL | Random | 104688 | $1,328.40 |
| NULL | NULL | NULL | Random | 105699 | $5,112.00 |
| NULL | NULL | NULL | Random | 105711 | $219.10 |
| NULL | NULL | NULL | Random | 105758 | $2,202.50 |
| NULL | NULL | NULL | Jason | 105739 | $2,278.04 |
| NULL | NULL | NULL | Jason | 105769 | $820.84 |
| NULL | NULL | NULL | Jason | 105770 | $797.12 |
| NULL | NULL | NULL | Dee Dee | 105702 | $2,244.30 |
| NULL | NULL | Customer subtotal: | NULL | subtotal | $24,157.91 |
| NULL | Tom subtotal: | NULL | NULL | subtotal | $24,157.91 |
| ght subtotal: | NULL | NULL | NULL | subtotal | $24,157.91 |
| NULL | NULL | NULL | NULL | GRAND TOTAL | $24,668.26 |
+-------------------+-----------------+--------------------+----------+--------------+-------------+
我知道这样的事情通常最好用SQL之外的语言来完成。但是,在项目的这一点上,这不是一个选择。我要么在SQL中做,要么我们必须处理'额外'数据。
*赞美http://www.sensefulsolutions.com/2010/10/format-text-as-table.html表格格式工具!
答案 0 :(得分:1)
正如其他人已经说过的那样,SQL Server(或任何相关的RDBMS)不会对输出顺序做出任何保证,除非您使用最外层的ORDER BY
子句指定所需的输出顺序。 {1}}。如果未指定SELECT
,则执行计划更改可以更改输出顺序。甚至查询执行时可用(=非忙)处理器的数量也会影响输出顺序。
ORDER BY
不需要引擎对数据进行排序。如果数据集足够大,SQL Server将使用Hash-Aggregate而不是Stream-Aggregate。如果发生这种情况,行将以随机顺序返回。同样,如果您需要特定顺序的行,则需要使用GROUP BY
指定。
ORDER BY
函数的结果与最终的行顺序无关。它仅受其自己的LAG()
子句中指定的顺序的影响。您甚至可以使用不同的订单生成多个OVER()
。
这意味着,您可能要在当前行的值和LAG
ed值之间进行的任何比较仍然是正确的。
答案 1 :(得分:0)
这应该有效:
WITH Names AS (
SELECT
Customer.CustomerID
, Customer.LastName + ', ' + Customer.FirstName + ' (' + Customer.Email + ')' AS 'Customer'
FROM
Customer
)
SELECT
Affiliate.Company AS 'Affiliate Company'
, Affiliate.Name AS 'Affiliate Name'
, CustomerLevel.Name AS 'Customer Company'
, Names.Customer as 'Customer'
, CASE GROUPING(Orders.OrderNumber) WHEN 1 THEN 'subtotal' ELSE CONVERT(VARCHAR,Orders.OrderNumber) END AS 'Order Number'
, '$' + CONVERT(VARCHAR,CONVERT(MONEY,SUM(Orders.OrderSubtotal)),1) AS 'Total Sales'
, LAG(Names.Customer, 1) OVER (ORDER BY Affiliate.Company, Affiliate.Name, CustomerLevel.Name, Names.Customer) AS 'Previous'
FROM Orders INNER JOIN
Affiliate ON Orders.AffiliateID = Affiliate.AffiliateID INNER JOIN
Customer ON Orders.CustomerID = Customer.CustomerID INNER JOIN
CustomerLevel ON Customer.CustomerLevelID = CustomerLevel.CustomerLevelID INNER JOIN
Names ON Customer.CustomerID = Names.CustomerID
GROUP BY
Affiliate.Company
, Affiliate.Name
, CustomerLevel.Name
, Names.Customer
, Orders.OrderNumber
WITH ROLLUP
HAVING
GROUPING(Orders.OrderNumber) < 1
OR
GROUPING(Names.Customer) = 1
OR
GROUPING(Affiliate.Company) = 1
OR
GROUPING(Affiliate.Name) = 1
OR
GROUPING(CustomerLevel.Name) = 1
ORDER BY
GROUPING(Affiliate.Company),
GROUPING(Affiliate.Name),
GROUPING(CustomerLevel.Name),
GROUPING(Names.Customer)