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

Posted

技术标签:

【中文标题】如何查询具有相同字段的两个表,仅当字段值相同时才返回id【英文标题】:How to query two tables that have the same field, that returns id only if field value is the same 【发布时间】:2020-09-19 15:47:54 【问题描述】:

我有两个表格(电子邮件和电话)指示是否打开了消息(阅读/收听)。我需要找到尚未打开消息的成员的 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

所以我需要一个只返回 Joe Smith 的查询

【问题讨论】:

样本数据对您的问题有很大帮助。 样本数据和期望的结果会有所帮助。 如果您想要“打开消息的成员的ID”,为什么要在代码中使用条件...AND opened = 'Y' 按要求添加样本数据 【参考方案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;

【讨论】:

戈登,非常感谢!你的最后一次更新正是我所需要的。当然是我需要提出的更具挑战性的查询之一。 Gordon,该解决方案确实需要一组括号将存在条件与不存在条件分开。

以上是关于如何查询具有相同字段的两个表,仅当字段值相同时才返回id的主要内容,如果未能解决你的问题,请参考以下文章

BigQuery:仅当字段具有特定值时才获取表中的最新行

仅当记录通过数据修改而更新时才更新日期

THINKPHP如何获取一个表2个字段中相同的数据

我在数据库中建了两个字段完全相同的表

仅当字段为空时才更新来自 select 语句的查询

sql两表联合查询“根据这两个字段值相同 查找其他字段值”怎么做?