想象一下以下两个表,分别命名为“Users”和“Orders”:
ID NAME
1 Foo
2 Bar
3 Qux
ID USER ITEM SPEC TIMESTAMP
1 1 12 4 20150204102314
2 1 13 6 20151102160455
3 3 25 9 20160204213702
我希望得到的输出是:
USER ITEM SPEC TIMESTAMP
1 12 4 20150204102314
2 NULL NULL NULL
3 25 9 20160204213702
换句话说:在用户和订单之间进行LEFT OUTER JOIN,如果您没有找到该用户的任何订单,则返回null,但如果找到一些,则只返回第一个(最早的一个)在时间戳上。)
如果我只使用LEFT OUTER JOIN,它将为用户1返回两行,我不希望这样。我想把LEFT OUTER JOIN嵌套在另一个选择中,它将GROUP BY其他字段并获取MIN(TIMESTAMP),但这不起作用,因为我需要在我的组中有“SPEC”,并且因为这两个命令有不同的规格,它们仍然出现。
对于如何实现理想结果的任何想法都表示赞赏。
答案 0 :(得分:3)
我能想到的最好方法是使用OUTER APPLY
SELECT *
FROM Users u
OUTER apply (SELECT TOP 1 *
FROM Orders o
WHERE u.ID = o.[USER]
ORDER BY TIMESTAMP DESC) ou
此外,在NON-Clustered
表格上创建以下ORDERS
索引将有助于您提高查询效果
CREATE NONCLUSTERED INDEX IX_ORDERS_USER
ON ORDERS ([USER], TIMESTAMP)
INCLUDE ([ITEM], [SPEC]);
答案 1 :(得分:2)
这应该可以解决问题:
SELECT Users.ID, Orders2.USER , Orders2.ITEM , Orders2.SPEC , Orders2.TIMESTAMP
FROM Users
LEFT JOIN
(
SELECT Orders.ID, Orders.USER , Orders.ITEM , Orders.SPEC , Orders.TIMESTAMP, ROW_NUMBER()
OVER (PARTITION BY ID ORDER BY TIMESTAMP DESC) AS RowNum
FROM Orders
) Orders2 ON Orders2.ID = Users.ID And RowNum = 1
答案 2 :(得分:1)
另一种方法是使用窗口函数作为Cte:
with Sorted as
(
select u.id as User, o.Item, o.Spec, o.Timestamp
row_number() over (partition by u.Id order by Timestamp) as Row
from Users u
left join orders o
on o.User = u.Id
)
select User, Item, Spec, Timestamp
from Sorted where Row = 1
答案 3 :(得分:1)
您会在this question找到很多建议。你有一个左连接的事实是你想要做的事情的偶然事件,所以这些答案应该很容易适应你的问题。我同意@MotoGP,对于SQLServer,OUTER APPLY
可能是最好的方法。它与Postgres的LATERAL JOIN
非常相似(在另一个链接中提到)。