我在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
感谢所有帮助或想法。
答案 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