在这个查询中,我需要显示左表中的所有记录,只显示右表中记录结果最晚的记录。
当前查询:
SELECT a.*, c.*
FROM users a
INNER JOIN payments c
ON a.id = c.user_ID
INNER JOIN
(
SELECT user_ID, MAX(date) maxDate
FROM payments
GROUP BY user_ID
) b ON c.user_ID = b.user_ID AND
c.date = b.maxDate
WHERE a.package = 1
这将返回连接有效的所有记录,但我需要显示所有用户,如果他们没有付款,则付款表中的字段应为空。
我可以使用联合来显示其他行:
SELECT a.*, c.*
FROM users a
INNER JOIN payments c
ON a.id = c.user_ID
INNER JOIN
(
SELECT user_ID, MAX(date) maxDate
FROM payments
GROUP BY user_ID
) b ON c.user_ID = b.user_ID AND
c.date = b.maxDate
WHERE a.package = 1
union
SELECT a.*, c.*
FROM users a
--here I would need to join with payments table to get the columns from the payments table,
but where the user doesn't have a payment yet
WHERE a.package = 1
使用联合的选项似乎不是一个好的解决方案,但这就是我尝试过的。
答案 0 :(得分:2)
因此,换句话说,您需要一个用户列表以及每个用户的最后一笔付款。
您可以使用OUTER APPLY
代替INNER JOIN
来获取每位用户的最后一笔付款。性能可能会更好,并且可以按照您希望的方式对没有付款的用户进行操作。
SELECT a.*, b.*
FROM users a
OUTER APPLY ( SELECT * FROM payments c
WHERE c.user_id = a.user_id
ORDER BY c.date DESC
FETCH FIRST ROW ONLY ) b
WHERE a.package = 1;
以下是相同概念的通用版本,不需要您的表格(适用于其他读者)。它给出了每个用户的数据库用户列表和最近修改过的对象。您可以正确地看到它包含没有对象的用户。
SELECT a.*, b.*
FROM all_users a
OUTER APPLY ( SELECT * FROM all_objects b
WHERE b.owner = a.username
ORDER BY b.last_ddl_time desc
FETCH FIRST ROW ONLY ) b
答案 1 :(得分:1)
我喜欢@Matthew McPeak的答案,但是OUTER APPLY是12c或更高,并且不管怎么说,它不是非常惯用的Oracle。这是一个直接的LEFT OUTER JOIN版本:
alias winpwd='cygpath -aw .'
BACKSLASHED="$(winpwd | tr / \\\\)"
如果性能有问题,您可能会发现以下性能更高,但为了简单起见,您最终会得到一个额外的“maxdate”列。
SELECT *
FROM users a
LEFT OUTER JOIN
(
-- retrieve the list of payments for just those payments that are the maxdate per user
SELECT payments.*
FROM payments
JOIN (SELECT user_id, MAX(date) maxdate
FROM payments
GROUP BY user_id
) maxpayment_byuser
ON maxpayment_byuser.maxdate = payments.date
AND maxpayment_byuser.user_id = payments.user_id
) b ON a.ID = b.user_ID
答案 2 :(得分:1)
使用row_number()
的通用方法对“最高日期”或“最近”或类似条件非常有用:
SELECT
*
FROM users a
LEFT OUTER JOIN (
-- determine the row corresponding to "most recent"
SELECT
payments.*
, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY date DESC) is_recent
FROM payments
) b ON a.ID = b.user_ID
AND b.is_recent = 1
(颠倒over子句中的ORDER BY
也会启用“最旧的”)