从多个表中检索多个列不存在或匹配行集(mysql php)

Posted

技术标签:

【中文标题】从多个表中检索多个列不存在或匹配行集(mysql php)【英文标题】:retrieve multiple columns from multiple tables not exists or match on rows set (mysql php) 【发布时间】:2016-01-03 05:10:42 【问题描述】:

我想就mysql查询寻求这个论坛的专业建议,我花了几个小时试图让它正确但无济于事。

所以事情是这样的。 Query1 下面我将从 5 个表中检索名称、雇主 ID、日期、班次 ID、班次标签、班次时间、商店 ID、商店名称、角色 ID 和角色标签,tblshifttblstore、@987654327 @、tblscheduleemployee

表 tblshift、tblstore、tblrole 和雇主通过它们各自的表中的 id 链接到 tblschedule。 php 变量 empstore 和 empdate 是从表单发布的值。

$query1 = '选择 a.name, a.empid, b.keydate, c.shiftid, c.shiftlabel, c.shifttime, c.shifttime2, d.storeid, d.storelabel, e.roleid , e.rolelabel from employee as a, tblschedule as b, tblshift as c, tblstore as d, tblrole as e where a.empid=b.empid and b.shiftid=c.shiftid and b.storeid=d.storeid and b .roleid=e.roleid 和 d.storeid='.$empstore.'和 b.keydate ="' . $empdate . '"';

上述查询工作正常,但我还想检索与此查询相反的查询,即查询中不存在的行。 我尝试在查询中使用“NOT EXIST”和“NOT IN”语句,但查询无法运行或行不正确。请参阅下面使用“NOT IN”和“NOT EXISTS”语句的查询。从 查询 2 和 3,您会发现我使用了 empid、keydate 和 shiftid,因为它们是我的 tblschedule 表中的主键,而其他列都是基于这种唯一性。

*$query2 = 'select a1.name, a1.empid, b1.keydate, c1.shiftid, c1.shiftlabel, c1.shifttime, c1.shifttime2, d1.storeid, d1.storelabel, e1.roleid, e1.rolelabel from employee as a1, tblschedule as b1, tblshift as c1, tblstore as d1, tblrole as e1 where a1.empid=b1.empid and b1.shiftid=c1.shiftid and b1.storeid=d1.storeid and b1.roleid=e1.roleid'
 . ' where (a1.empid, b1.keydate, c1.shiftid) not in (select a2.empid, b2.keydate, c2.shiftid from employee as a2, tblschedule as b2, tblshift as c2, tblstore as d2, tblrole as e2 where a2.empid=b2.empid and b2.shiftid=c2.shiftid and b2.storeid=d2.storeid and b2.roleid=e2.roleid and d2.storeid='.$empstore.' and b2.keydate ="' . $empdate . '")';


$query3 = 'select a1.name, a1.empid, b1.keydate, c1.shiftid, c1.shiftlabel, c1.shifttime, c1.shifttime2, d1.storeid, d1.storelabel, e1.roleid, e1.rolelabel from employee as a1, tblschedule as b1, tblshift as c1, tblstore as d1, tblrole as e1 where a1.empid=b1.empid and b1.shiftid=c1.shiftid and b1.storeid=d1.storeid and b1.roleid=e1.roleid'
 . ' where not exists (select 1 from employee as a2, tblschedule as b2, tblshift as c2, tblstore as d2, tblrole as e2 where a2.empid=b2.empid and b2.shiftid=c2.shiftid and b2.storeid=d2.storeid and b2.roleid=e2.roleid and d2.storeid='.$empstore.' and b2.keydate ="' . $empdate . '" and a1.empid=a2.empid and b1.keydate=b2.keydate and c1.shiftid=c2.shiftid)';*

关于查询的复杂部分是我试图从其他表的多个列中收集数据,并且我还根据唯一列 empid、keydate 和 shiftid 过滤数据。我在下面的这个网站上找到了一些来源,但无法正常工作。

How to retrieve non-matching results in mysql

get the opposite results from a SELECT query

mysql "Where not in" using two columns

提前致谢,期待在这里向大家学习。

问候, 丹尼斯

【问题讨论】:

查看连接。左和内连接 【参考方案1】:

“有效”的原始查询格式为:

SELECT a.name
     , a.empid
     , b.keydate
     , c.shiftid
     , c.shiftlabel
     , c.shifttime
     , c.shifttime2
     , d.storeid
     , d.storelabel
     , e.roleid
     , e.rolelabel
  FROM employee  a
  JOIN tblschedule  b
    ON b.empid = a.empid
  JOIN tblshift  c
    ON c.shiftid = b.shiftid
  JOIN tblstore  d
    ON d.storeid = b.storeid
  JOIN tblrole  e
    ON e.roleid = b.roleid
 WHERE d.storeid = :empstore
   AND b.keydate = :empdate

这应该相当于OP查询。它只是被重新格式化以更易辨认;用 JOIN 关键字替换连接操作的老式逗号语法,并将连接谓词重新定位到 ON 子句。


我不明白为什么 OP 不能仅仅否定 WHERE 子句中的谓词。也就是说,将上面查询中的WHERE 子句替换为:

 WHERE ( d.storeid <> :empstore )
    OR ( b.keydate <> :empdate OR b.keydate IS NULL )

在我看来,这将返回 OP 想要返回的行集。

但也许有一些我不明白的地方。


在更一般的情况下,要从查询返回的一组行中排除与另一个查询返回的行匹配的行...

使用 anti-join 模式是规范的方法。这是一个外连接操作...返回一个查询的所有行,以及另一个查询的匹配行,然后排除找到匹配项的行。

在这种特殊情况下,查询将采用以下形式:

SELECT q1.*
  FROM ( 
         query1 
       ) q1 
  LEFT
  JOIN ( 
         query2
       ) q2
    ON q2.empid   = q1.empid
   AND q2.keydate = q1.keydate
   AND q2.shiftid = q1.shiftid 
 WHERE q2.empid IS NULL

此查询表示返回 q1 中的所有行,以及 q2 中的匹配行,但不包括在 q2 中找到匹配项的行。诀窍是在 q2.empid 中测试 NULL 值的 WHERE 子句。连接谓词向我们保证,当在 q2 中找到匹配行时,q2.empid 将是非 NULL。因此,q2.empid 中唯一具有 NULL 值的行是 q1 中没有匹配行的行。

q2 将是原始查询; OP 确实想要返回的行集。

q1 将是原始查询,省略 WHERE 子句。所以,所有的行...... OP 想要返回的行以及 OP 想要排除的行。


综合起来,查询可能如下所示:

SELECT q1.*
  FROM ( -- query1 - all rows including those we are going to exclude (omit WHERE clause)
         SELECT a.name
              , a.empid
              , b.keydate
              , c.shiftid
              , c.shiftlabel
              , c.shifttime
              , c.shifttime2
              , d.storeid
              , d.storelabel
              , e.roleid
              , e.rolelabel
           FROM employee  a
           JOIN tblschedule  b
             ON b.empid = a.empid
           JOIN tblshift  c
             ON c.shiftid = b.shiftid
           JOIN tblstore  d
             ON d.storeid = b.storeid
           JOIN tblrole  e
             ON e.roleid = b.roleid
       ) q1 
  LEFT
  JOIN (
         -- query2 - the rows that are going to be excluded
         SELECT a.name
              , a.empid
              , b.keydate
              , c.shiftid
              , c.shiftlabel
              , c.shifttime
              , c.shifttime2
              , d.storeid
              , d.storelabel
              , e.roleid
              , e.rolelabel
           FROM employee  a
           JOIN tblschedule  b
             ON b.empid = a.empid
           JOIN tblshift  c
             ON c.shiftid = b.shiftid
           JOIN tblstore  d
             ON d.storeid = b.storeid
           JOIN tblrole  e
             ON e.roleid = b.roleid
          WHERE d.storeid = :empstore
            AND b.keydate = :empdate
       ) q2
    ON q2.empid   = q1.empid
   AND q2.keydate = q1.keydate
   AND q2.shiftid = q1.shiftid 
 WHERE q2.empid IS NULL

但同样,对于这种特殊情况,反连接模式似乎是一种简单地否定 WHERE 子句中的谓词的迂回方式。

【讨论】:

如果 keydate 可以为 NULL,并且我们想“匹配”keydate 具有 NULL 值的行,我们可以使用 MySQL 空安全比较器.... @ 987654334@(宇宙飞船符号)。连接谓词向我们保证empidshiftid 不会为NULL。)。如果这不是 OP 正在寻找的行集,那么我们需要对规范进行更多说明……“相反行”实际上是什么意思。【参考方案2】:

感谢您的详细解释和撰写,很抱歉回复晚了,因为我正在尝试消化信息并尝试您的示例。

我的最终查询如下所示并且正在运行。

      $query = 'SELECT q1.* FROM (SELECT a.name , a.empid, b.keydate, c.shiftid, c.shiftlabel, c.shittime, c.shittime2, d.storeid, d.storelabel, e.roleid, e.rolelabel FROM tblschedule b JOIN employee a ON b.empid = a.empid JOIN tblshift c ON c.shiftid = b.shiftid JOIN tblstore d ON d.storeid = b.storeid JOIN tblrole e ON e.roleid = b.roleid) q1' 
  .' LEFT JOIN (SELECT a.name , a.empid, b.keydate, c.shiftid, c.shiftlabel, c.shittime, c.shittime2, d.storeid, d.storelabel, e.roleid, e.rolelabel FROM tblschedule b JOIN employee a ON b.empid = a.empid JOIN tblshift c ON c.shiftid = b.shiftid JOIN tblstore d ON d.storeid = b.storeid JOIN tblrole e ON e.roleid = b.roleid WHERE d.storeid ='.$empstore.' AND b.keydate ="'. $empstartdate.'") q2'
   .' ON q2.empid = q1.empid'
   .' AND q2.keydate = q1.keydate'
   .' AND q2.shiftid = q1.shiftid'
   .' WHERE q2.storeid IS NULL and q2.keydate is null and q2.empid is null';

顺便说一句,这是我在这个网站上发布的第一个问题,我该如何将您的答案标记为正确的答案。

谢谢,祝你有美好的一天。

【讨论】:

以上是关于从多个表中检索多个列不存在或匹配行集(mysql php)的主要内容,如果未能解决你的问题,请参考以下文章

MySQL基础:检索数据

如何从具有多个关联的两个 MySQL 表中检索数据

MySQL必知应会-第4章-检索数据

mysql必知必会--检 索 数 据

用于从多个表中检索数据的 Sql 查询

SQL 表变量 - 添加检查匹配行集是不是存在的约束