Sql 只从第二个表中连接一行,如果不存在行,则返回null

Sql 只从第二个表中连接一行,如果不存在行,则返回null,sql,oracle,join,inner-join,Sql,Oracle,Join,Inner Join,在这个查询中,我需要显示左表中的所有记录,并且只显示右表中结果为最高日期的记录 当前查询: 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

在这个查询中,我需要显示左表中的所有记录,并且只显示右表中结果为最高日期的记录

当前查询:

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

使用工会的选项似乎不是一个好的解决方案,但这正是我所尝试的。

因此,换句话说,您需要一个用户列表以及每个用户的最后付款

您可以使用
OUTER APPLY
而不是
internal 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

我喜欢@Matthew McPeak的答案,但从历史上看,OUTER APPLY的温度是12摄氏度或更高,并不是非常地道的甲骨文。这是一个直接的左外连接版本:

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 
如果性能是一个问题,您可能会发现以下性能更高,但为了简单起见,您将得到一个额外的“maxdate”列


使用
行编号()
的通用方法对于“最早日期”或“最近”或类似情况非常有用:

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子句中按颠倒顺序也可以启用“最旧的”)

我有12c,所以他的答案有效。但我喜欢你对+1的态度,你能再解释一下“最老的”吗+1在“分区”中查看
over(按…顺序按…分区)上的内容
orderby
控制哪一行的值为1。如果您颠倒顺序,请将得到一个的行颠倒过来。也就是说,你可以找到“最早的”或颠倒它,找到“最早的”。我建议你慢慢来,直到感觉到为止。
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