如何查询具有相同字段的两个表,仅当字段值相同时才返回id

时间:2020-09-19 15:47:54

标签: mysql sql

我有两个表(电子邮件和电话),用于指示是否打开了一条消息(已读/已听)。我需要找到尚未打开消息的成员的ID(他们可能已经发送了电子邮件并被呼叫)。因此,唯一没有收到消息的情况就是他们没有打开电子邮件或接听电话。

我有一个看起来像这样的查询,以了解他们是否打开了它:

SELECT person_id, last_name, first_name
      FROM person 
     WHERE person_id IN (
          SELECT DISTINCT person_id 
          FROM (
            SELECT person_id
              FROM msg_email WHERE message_id = ? AND opened = 'Y'
            UNION ALL
            SELECT person_id
              FROM msg_voice WHERE message_id = ? AND opened = 'Y') tt
         )
 ORDER BY last_name ASC, first_name ASC"

但是,这仅适用于了解是否通过任何一种交付方式将其打开。

如何处理查询以查找接收到消息的人的id(存在于两个表之一),但两个表中的唯一打开值为“ N”?

样本数据 人桌

person_id  firstname lastname
    1         Joe       Smith
    2         Tom       Jones

msg_email表

message_id  person_id  opened
    1            1       N
    1            2       Y

msg_phone表

message_id  person_id  opened
    1            1        N
    1            2        N

所以我需要一个只返回乔·史密斯的查询

1 个答案:

答案 0 :(得分:1)

嗯,一种方法是一系列EXISTS / IN条件:

SELECT p.person_id, p.last_name, p.first_name
FROM person p
WHERE EXISTS (SELECT 1
              FROM msg_email e
              WHERE e.person_id = p.person_id AND e.opened = 'N'
             ) AND
      NOT EXISTS (SELECT 1
                  FROM msg_email e
                  WHERE e.person_id = p.person_id AND e.opened = 'Y'
                 ) AND
      EXISTS (SELECT 1
              FROM msg_voice v
              WHERE v.person_id = p.person_id AND v.opened = 'N'
             ) AND
      NOT EXISTS (SELECT 1
                  FROM msg_voice v
                  WHERE v.person_id = p.person_id AND v.opened = 'Y'
                 )
ORDER BY last_name ASC, first_name ASC;

我推荐EXISTS胜过IN,因为它通常具有更好的性能。如果您在msg_email(person_id, opened)msg_voice(person_id, opened)上有索引,那将是正确的。

编辑:

在我看来,您希望在两个表中都没有'N',而在两个表中都没有'Y'。逻辑类似,但是:

SELECT p.person_id, p.last_name, p.first_name
FROM person p
WHERE (EXISTS (SELECT 1
               FROM msg_email e
               WHERE e.person_id = p.person_id AND e.opened = 'N'
              ) OR
       EXISTS (SELECT 1
               FROM msg_voice v
               WHERE v.person_id = p.person_id AND v.opened = 'N'
              )
      ) AND
      NOT EXISTS (SELECT 1
                  FROM msg_email e
                  WHERE e.person_id = p.person_id AND e.opened = 'Y'
                 ) AND
      NOT EXISTS (SELECT 1
                  FROM msg_voice v
                  WHERE v.person_id = p.person_id AND v.opened = 'Y'
                 )
ORDER BY last_name ASC, first_name ASC;