Mysql SQL使用空值连接3个表

Mysql SQL使用空值连接3个表,mysql,sql,join,mysql-5.6,Mysql,Sql,Join,Mysql 5.6,我有一个查询,返回成员,他们最后的访问和他们最后的付款。我的问题是,如果没有访问和/或付款,它不会返回成员 我以前没有包括最后的访问,然后我有一个查询,使用左和右连接,而不是内部连接,但是当我添加访问表时,我收到了som帮助以包括它,但我们没有注意到,我们在访问或支付中缺少了空值的成员 我尝试过在没有任何运气的情况下应用左连接和右连接。 我还尝试添加例如“OR(pt.member\u id为NULL)”也没有成功 SELECT mr.member_id, mr.name,

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

我以前没有包括最后的访问,然后我有一个查询,使用左和右连接,而不是内部连接,但是当我添加访问表时,我收到了som帮助以包括它,但我们没有注意到,我们在访问或支付中缺少了空值的成员

我尝试过在没有任何运气的情况下应用左连接和右连接。 我还尝试添加例如“OR(pt.member\u id为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

下面的版本在任何地方都使用左连接,可能会得到您想要的结果:

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;

以下版本在任何地方都使用左联接,可能会得到所需的结果:

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;

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

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;
对于绩效,您需要关于
付款(会员id,日期描述,学期)
访问(会员id,日期描述)
的索引

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

在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

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

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;
对于绩效,您需要关于
付款(会员id,日期描述,学期)
访问(会员id,日期描述)
的索引

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

在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

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

从第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;

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

从第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;

LEFT JOIN
如果主表中的记录较多,则肯定会给您提供空访问/付款,因为这些ID不会出现在另一个联接表中。如果情况并非如此,请尝试通过单独运行子查询进行调试,检查单独运行时访问/付款是否遇到任何空值。

如果主表中的记录较多,则肯定会给您提供空访问/付款,因为这些ID不会出现在另一个连接表中。如果情况并非如此,请尝试通过单独运行子查询进行调试,检查单独运行时访问/付款是否遇到任何空值。

对Thorsten Kettner的答案稍加调整即可:

谢谢大家:)


对托尔斯滕·凯特纳的回答稍加修改就成功了:

谢谢大家:)


事实上,加入左派是处理你的情况的一种方法。您使用左联接到底尝试了什么?了解左联接返回的内容:行上的内部联接联合所有由null扩展的不匹配的左表行。始终知道作为外部联接的一部分,您需要什么样的内部联接。上的WHERE或内部联接,在上的外部联接删除任何由NULL扩展的行后,要求右[sic]表列不为NULL,即在行上只保留内部联接,即“将外部联接转换为内部联接”。这很可能是您的左连接问题,但即使它没有达到您期望的效果,您也不会这样问。请在代码问题中给出一个--cut&paste&runnable代码;具有期望和实际输出的示例输入(包括逐字错误消息);标签和清晰的说明和解释。这包括您能给出的最少代码,即您显示为OK的代码,由您显示为not OK的代码扩展。(调试基础。)事实上,左键连接是处理您的情况的一种方法。您使用左联接到底尝试了什么?了解左联接返回的内容:行上的内部联接联合所有由null扩展的不匹配的左表行。始终知道作为外部联接的一部分,您需要什么样的内部联接。上的WHERE或内部联接,在上的外部联接删除任何由NULL扩展的行后,要求右[sic]表列不为NULL,即在行上只保留内部联接,即“将外部联接转换为内部联接”。这很可能是您的左连接问题,但即使它没有达到您期望的效果,您也不会这样问。请在代码问题中给出一个--cut&paste&runnable代码;具有期望和实际输出的示例输入(包括逐字错误消息);标签和清晰的说明和解释。这包括您能给出的最少代码,即您显示为OK的代码,由您显示为not OK的代码扩展。(调试基础。)这是可行的,但即使在索引查询之后7s@AntwonP . . . 这与其他方法相比又如何呢?这是可行的,但即使在索引查询之后也需要7s@AntwonP . . . 这与其他方法相比又如何呢?嗨,谢谢你的快速回复。我使用的是MySQL 5.6,在尝试您的查询时,我得到以下错误:您的SQL语法有错误;查看与您的MySQL服务器版本对应的手册,了解使用near'(按成员id划分)作为付款最后日期的正确语法,其中(成员id,d'位于第21Oh行,对此表示抱歉。