公用表表达式中的UNION&ORDER两个表

时间:2019-01-15 09:40:06

标签: sql-server sql-server-2008-r2 common-table-expression sql-cte

我在SQL存储过程中有一个CTE,它<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <p><a data-id="1">Select Row 1</a></p> <p><a data-id="2">Select Row 2</a></p> <p><a data-id="3">Select Row 3</a></p> <p><a data-id="4">Select Row 4</a></p> <table id="mtable" class="table table-hover b-t"> <thead> <tr> <th>#</th> <th>First Name</th> <th>Last Name</th> <th>Username</th> </tr> </thead> <tbody> <tr id="row1"> <td>1</td> <td>Mark</td> <td>Otto</td> <td>@mdo</td> </tr> <tr id="row2"> <td>2</td> <td>Otto</td> <td>@TwBootstrap</td> <td>123</td> </tr> <tr id="row3"> <td>3</td> <td>Jacob</td> <td>Thornton</td> <td>@fat</td> </tr> <tr id="row4"> <td>4</td> <td>Larry the Bird</td> <td>@twitter</td> <td>abc</td> </tr> </tbody> </table>从两个数据库中获取值-值是客户编号和该客户的最后订购日期。

这是原始SQL-

UNION

示例结果:

;WITH CTE_last_order_date AS
(
SELECT c1.customer ,MAX(s2.dt_created) AS last_order_date
FROM customers c1 WITH (NOLOCK)

LEFT JOIN archive_orders s2 WITH (NOLOCK)
ON c1.customer = s2.customer

GROUP BY c1.customer

UNION ALL

SELECT c1.customer ,MAX(s1.dt_created) AS last_order_date
FROM customers c1 WITH (NOLOCK)

LEFT JOIN orders s1 WITH (NOLOCK)
ON c1.customer = s1.customer

GROUP BY c1.customer
)

这显然不适用customer, last_order_date CF122595, 2011-11-15 15:30:22.000 CF122595, 2016-08-15 10:01:51.230 (2 row(s) affected) 不同记录规则,因为日期值不匹配,这意味着SQL从两个表返回了最大值(即最终记录集未完全不同)

为解决此问题,我尝试了另一种从this question借用的方法并实现了分组:

UNION

示例结果:

;WITH CTE_last_order_date AS
(
SELECT max(last_order_date) as 'last_order_date', customer
FROM (
SELECT distinct cust.customer, max(s2.dt_created) AS last_order_date, '2' AS 'group'
FROM customers c1 WITH (NOLOCK)

LEFT JOIN archive_orders s2 WITH (NOLOCK)
ON c1.customer = s2.customer

GROUP BY c1.customer

UNION 

SELECT distinct c1.customer, max(sord.dt_created) AS last_order_date, '1' AS 'group'
FROM customers c1 WITH (NOLOCK)

LEFT JOIN orders s1 WITH (NOLOCK)
ON cust.customer = sord.customer

GROUP BY
   c1.customer
   ) AS t
GROUP  BY customer
ORDER  BY MIN('group'), customer
)

这有一个很好的区别(hah),可以正常运行,直到陷入阻止在Common Table Expressions中阻止customer, last_order_date CF122595, 2016-08-15 10:01:51.230 (1 row(s) affected) 的规则为止,这是选择最低组(这意味着实时订单(group)的必要条件) 1),其日期需要优先于存档(组2)。

ORDER BY

感谢所有帮助或想法。

4 个答案:

答案 0 :(得分:2)

与其分组,然后合并,然后再次分组,何不合并订单表并从那里开始工作?

SELECT c1.customer ,MAX(s2.dt_created) AS last_order_date
FROM customers c1
INNER JOIN (select customer, dt_created from archive_orders
union all select customer, dt_created from orders) s2
ON c1.customer = s2.customer
GROUP BY c1.customer

请记住,在SQL中,您的工作是告诉系统您想要什么,而不是要遵循哪些步骤/过程以获得这些结果。上面从逻辑上描述了我们想要的-我们想要每个客户订单中的最后一个订单日期,并且我们不在乎是已存档订单还是未存档订单。

由于我们将在GROUP BY行为期间将订单信息减少到单个行(每个客户),因此我们 也不需要{{1} }删除重复项,因此我已切换到UNION

(我承认,我目前无法真正看到UNION ALL应该添加到组合中的内容,因此我没有尝试将其添加到此处。如果要纳入CTE,然后思考一下事实,即CTE与表和视图一样没有固有顺序。唯一影响结果行顺序的ORDER BY子句是应用于最外层/最后一层的子句ORDER BY


SELECT的优先级赋予orders

archived_orders

答案 1 :(得分:1)

另一种方法可能是只从没有当前客户的存档表中获取客户。像这样:

WITH CurrentLastOrders(customer, last_order_date) AS    -- Get current last orders
(
    SELECT o.customer, max(o.dt_created) AS last_order_date
    FROM orders s WITH (NOLOCK) ON c.customer = o.customer
    GROUP BY o.customer
),
ArchiveLastOrders(customer, last_order_date) AS -- Get archived last orders where customer does not have a current order
(
    SELECT o.customer, max(o.dt_created) AS last_order_date
    FROM archive_orders o WITH (NOLOCK)
    WHERE NOT EXISTS ( SELECT *
                        FROM CurrentLastOrders lo
                        WHERE o.customer = lo.customer)
    GROUP BY o.customer
),
AllLastOrders(customer, last_order_date) AS -- All customers with orders
(
    SELECT customer, last_order_date
    FROM CurrentLastOrders
    UNION ALL
    SELECT customer, last_order_date
    FROM ArchiveLastOrders
)
AllLastOrdersPlusCustomersWithNoOrders(customer, last_order_date) AS    -- All customerswith latest order if they have one
(
    SELECT customer, last_order_date
    FROM AllLastOrders
    UNION ALL
    SELECT customer, null
    FROM customers c WITH (NOLOCK)
    WHERE NOT EXISTS ( SELECT *
                        FROM AllLastOrders lo
                        WHERE c.customer = lo.customer)
)

答案 2 :(得分:1)

我不会尝试嵌套SQL以获得不同的结果集,这与在两个联合查询中按客户分组的逻辑相同。 如果您想要一个独特的有序集合,可以在CTE之外进行

怎么样:

;WITH CTE_last_order_date AS
(
   SELECT c1.customer ,s2.dt_created AS last_order_date, '2' AS 'group'
   FROM customers c1 WITH (NOLOCK)
   LEFT JOIN archive_orders s2 WITH (NOLOCK) ON c1.customer = s2.customer

   UNION ALL

   SELECT c1.customer ,s1.dt_created AS last_order_date, '1' AS 'group'
   FROM customers c1 WITH (NOLOCK)
   LEFT JOIN orders s1 WITH (NOLOCK) ON c1.customer = s1.customer

)
SELECT customer, MAX(last_order_date)
FROM CTE_last_order_date
GROUP BY customer 
ORDER BY MIN('group'), customer

答案 3 :(得分:1)

如果您将所有可能的行合并在一起,然后计算出row_number,按客户划分并按“ group”排序,然后last_order_date降序,则可以选择所有row = 1以为每个客户提供“前1名”

;WITH CTE_last_order_date AS
(
SELECT max(last_order_date) as 'last_order_date', customer
FROM (
SELECT distinct cust.customer, max(s2.dt_created) AS last_order_date, '2' AS 'group'
FROM customers c1 WITH (NOLOCK)

LEFT JOIN archive_orders s2 WITH (NOLOCK)
ON c1.customer = s2.customer

GROUP BY c1.customer

UNION 

SELECT distinct c1.customer, max(sord.dt_created) AS last_order_date, '1' AS 'group'
FROM customers c1 WITH (NOLOCK)

LEFT JOIN orders s1 WITH (NOLOCK)
ON cust.customer = sord.customer

GROUP BY
   c1.customer
   ) AS t
GROUP  BY customer

)
,   --row_number below is 'per customer' and can be used to make rn=1 the top 1 for each customerid
ROWN AS (SELECT Customer,last_order_date,[group], row_number() OVER(partition by customer order by [group] ASC, sord.dt_created DESC) AS RN)
SELECT * FROM Rown WHERE Rown.rn = 1