SQL连接3个具有空值的表

时间:2019-07-11 13:44:58

标签: mysql sql join mysql-5.6

我有一个查询,该查询返回成员,他们的上次访问和最后的付款。我的问题是,没有访问和/或付款,它不会返回会员。

我以前没有包括最后一次访问,然后我用LEFT和RIGHT JOINs而不是INNER进行查询,但是当我添加访问表时,我得到了包括它的索姆帮助,但我们没有注意到我们缺少成员访问或付款中的值为空。

我尝试应用LEFT和RIGHT JOIN没有任何运气。 我也尝试添加例如。 “ OR(pt.member_id IS NULL)”也没有成功。

SELECT
    mr.member_id, 
    mr.name, 
    mr.tag, 
    pt.semester, 
    pt.date, 
    vt.date, 
FROM 
    members mr
INNER JOIN 
    payment pt 
ON 
    pt.member_id = mr.member_id 
    INNER JOIN 
        ( SELECT 
            member_id, 
            MAX(payment_id) max_value 
        FROM 
            payment 
        GROUP BY    
            member_id ) pt2 
    ON 
        pt.member_id = pt2.member_id 
    AND 
        pt.payment_id = pt2.max_value   
INNER JOIN 
    visit vt 
ON 
    vt.member_id = mr.member_id 
    INNER JOIN  
        ( SELECT    
            member_id, 
            MAX(date) max_visit_value 
        FROM 
            visit 
        GROUP BY 
            member_id ) vt2 
    ON 
        vt.member_id = vt2.member_id 
    AND 
        vt.date = vt2.max_visit_value

我想得到一个访问和/或付款可以为空的结果。

我希望我有道理,希望有人可以帮助我:)

MySQL 5.6

5 个答案:

答案 0 :(得分:0)

以下在各处使用左连接的版本可能会为您提供所需的结果:

SELECT
    mr.member_id,
    mr.name,
    mr.tag,
    pt.semester,
    pt.date,
    vt.date,
FROM members mr
LEFT JOIN payment pt
    ON pt.member_id = mr.member_id
LEFT JOIN
(
    SELECT member_id, MAX(payment_id) max_value
    FROM payment
    GROUP BY member_id
) pt2
    ON pt.member_id = pt2.member_id AND pt.payment_id = pt2.max_value
LEFT JOIN visit vt
    ON vt.member_id = mr.member_id
LEFT JOIN
(
    SELECT member_id, MAX(date) max_visit_value
    FROM visit
    GROUP BY member_id
) vt2
    ON vt.member_id = vt2.member_id AND vt.date = vt2.max_visit_value;

答案 1 :(得分:0)

相关子查询可能是最简单的解决方案:

SELECT mr.member_id, mr.name, mr.tag, 
       (SELECT pt.semester
        FROM payment pt
        WHERE pt.member_id = mr.member_id
        ORDER BY pt.date DESC
        LIMIT 1
       ) as last_payment_semester
       (SELECT pt.date
        FROM payment pt
        WHERE pt.member_id = mr.member_id
        ORDER BY pt.date DESC
        LIMIT 1
       ) as last_payment_date
       (SELECT MAX(vt.date,)
        FROM visit vt
        WHERE vt.member_id = mr.member_id
        ORDER BY vt.date DESC
        LIMIT 1
       ) as last_visit_date
FROM members mr;

为了提高性能,您希望在payment(member_id, date desc, semester)visit(member_id, date desc)上建立索引。

诚然,对于日期和学期,必须将基本上相同的子查询重复两次,这有点不雅。

在MySQL 8+中,您可以使用窗口函数:

SELECT mr.member_id, mr.name, mr.tag, pt.semester, pt.date, vt.date
FROM members mr LEFT JOIN
     (SELECT pt.*,
             ROW_NUMBER() OVER (PARTITION BY pt.member_id ORDER BY pt.date DESC) as seqnum
      FROM payment pt
     ) pt
     ON pt.member_id = mr.member_id AND pt.seqnum = 1 LEFT JOIN
     (SELECT pt.*,
             ROW_NUMBER() OVER (PARTITION BY vt.member_id ORDER BY vt.date DESC) as seqnum
      FROM visit vt
     ) vt
     ON vt.member_id = mr.member_id AND vt.seqnum = 1

答案 2 :(得分:0)

这里最大的问题是会员可以进行很多付款和多次访问。您只想显示每个最新的。这对于访问很容易,因为您只想显示(最大)日期。但是,对于付款,您还想显示属于最长日期的学期。如果学期像日期一样升序,那么再简单一遍:使用MAX(semester)。如果不是,则必须检索最大日期 row

从MySQL 8开始:

SELECT
  mr.member_id, 
  mr.name, 
  mr.tag, 
  pt.semester, 
  pt.date, 
  vt.date 
FROM members mr
LEFT JOIN 
(
  SELECT
    member_id,
    semester,
    date,
    MAX(date) OVER (PARTITION BY member_id) AS last_date
  FROM payment
) pt ON pt.member_id = mr.member_id AND pt.dateb = pt.last_date
LEFT JOIN
(
  SELECT    
    member_id, 
    MAX(date) AS max_visit_value 
  FROM visit 
  GROUP BY member_id
) vt ON vt.member_id = mr.member_id 
ORDER BY mr.member_id;

在早期版本中:

SELECT
  mr.member_id, 
  mr.name, 
  mr.tag, 
  pt.semester, 
  pt.date, 
  vt.date 
FROM members mr
LEFT JOIN 
(
  SELECT
    member_id,
    semester,
    date
  FROM payment
  WHERE (member_id, date) IN 
  (
    SELECT member_id, MAX(date)
    FROM payment
    GROUP BY member_id
  )
) pt ON pt.member_id = mr.member_id
LEFT JOIN
(
  SELECT    
    member_id, 
    MAX(date) AS max_visit_value 
  FROM visit 
  GROUP BY member_id
) vt ON vt.member_id = mr.member_id 
ORDER BY mr.member_id;

答案 3 :(得分:0)

如果主表中的记录更多,那么

LEFT JOIN可以为您带来帮助,因为这些ID在其他联接表中不会存在,因此肯定会给您带来空访问/付款。如果不是这种情况,也请尝试通过运行子查询单独进行调试,以检查单独运行时是否存在访问/付款遇到的任何空值。

答案 4 :(得分:0)

对Thorsten Kettner的答案进行了一些微调,使其起作用:

谢谢大家:)

SELECT
    mr.member_id,
    mr.name,
    mr.tag,
    pt.semester,
    pt.date,
    vt.date
FROM members mr

LEFT JOIN
(
    SELECT 
        member_id, 
        semester, 
        date        
    FROM payment
    WHERE ( member_id, date ) IN
    (
        SELECT 
            member_id, 
            MAX(date)
        FROM 
            payment
        GROUP BY 
            member_id
    )
 ) pt ON pt.member_id = mr.member_id

 LEFT JOIN
 (
    SELECT
        member_id,
        date,
        door
    FROM visit
    WHERE ( member_id, date ) IN
    (
        SELECT 
            member_id, 
            MAX(date)
        FROM 
            visit
        GROUP BY 
            member_id
    )
 ) vt ON vt.member_id = mr.member_id