繁体   English   中英

从第二个表中仅联接一行,如果不存在任何行,则返回null

[英]JOIN only one row from second table and if no rows exist return null

在此查询中,我需要显示左表中的所有记录,而只显示右表中结果为最高日期的记录。

当前查询:

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

这将返回联接有效的所有记录,但是我需要显示所有用户,并且如果他们还没有付款,则付款表中的字段应为null。

我可以使用联合来显示其他行:

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代替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

我喜欢@Matthew McPeak的回答,但从历史上看,OUTER APPLY为12c或更高,并且不是非常惯用的Oracle。 这是一个直接的LEFT OUTER JOIN版本:

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
(
    -- retrieve the list of payments for just those payments that are the maxdate per user
    SELECT *
    FROM (
           SELECT payments.*,
                  MAX(date) OVER (PARTITION BY user_id) maxdate
             FROM payments
         ) max_payments
    WHERE date = maxdate
) b ON a.ID = b.user_ID 

使用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也会启用“最早的”)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM