SQL Server 2012将LAG与ROLLUP一起使用以删除字段中的连续重复项 - 结果已反转

时间:2013-04-12 21:01:25

标签: sql sql-server

我有一个使用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表格格式工具!

2 个答案:

答案 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)