dtgv52982 2016-01-03 05:10
浏览 45
已采纳

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

I would like to seek the professional advice of this forum on a mysql query which have I have spend hours trying to get it right but to no avail.

So it goes like this. Query1 below which I will retrieve the name, employer id, date, shift id, shift label, shift time, store id, store name, role id and role label from 5 tables, tblshift, tblstore, tblrole, tblschedule and employee.

The tables tblshift, tblstore, tblrole and employer are linked to the tblschedule through their respective ids in their tables. The php variables empstore and empdate are values that are posted from the form.

$query1 = '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 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 and d.storeid='.$empstore.' and b.keydate ="' . $empdate . '"';

The above query works correctly but I would also like to retrieve the opposite of this query which are the rows not present in the query. I have tried to use the 'NOT EXIST' and also 'NOT IN' statements in my query but either the query could not run or the rows are not correct. Please see below queries using 'NOT IN' and 'NOT EXISTS'statements. From query 2 and 3, you will observe that I have used empid, keydate and shiftid because these are primary keys in my tblschedule table and the other columns are based on this uniqueness.

*$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)';*

The complicated part about the queries is that I am trying to collect datas from multiple columns of other tables and I am also filtering the datas based on the unique columns empid, keydate and shiftid. I have found some sources from this website below but could not get it working.

How to retrieve non-matching results in mysql

get the opposite results from a SELECT query

mysql "Where not in" using two columns

Thanks in advance and look forward to learning from all of you here.

regards, dennis

  • 写回答

2条回答 默认 最新

  • dragon88112 2016-01-03 06:17
    关注

    The original query that "works" is of the form:

    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
    

    This should be equivalent to OP query. It's just reformatted to be more decipherable; replacing the old-school comma syntax for the join operations with the JOIN keyword, and relocating the join predicates to the ON clause.


    I'm not understanding why OP can't just negate the predicates in the WHERE clause. That is, replace the WHERE clause in the query above with something like:

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

    It seems to me that would return the set of rows OP wants to return.

    But maybe there's something I'm not understanding.


    In the more general case, to exclude from a set of rows returned by a query, rows that match rows returned by another query...

    using an anti-join pattern is the normative approach. That's an outer join operation... return all rows from one query, along matching rows from another query, and then excluding the rows where a match was found.

    In this particular case, the query would be of this form:

    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
    

    This query says to return all rows from q1, along with matching rows from q2, but excluding rows where a match was found in q2. The trick is the WHERE clause that tests for a NULL value in q2.empid. The join predicate guarantees us that q2.empid will be non-NULL when a matching row is found in q2. So the only rows that will have a NULL value in q2.empid are rows from q1 that didn't have a matching row.

    q2 would be the original query; the set of rows that OP does not want to return.

    q1 would be the original query, omitting the WHERE clause. So, all of the rows... the rows OP wants to return along with the rows that OP wants to exclude.


    Putting that all together, the query might look something like this:

    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
    

    But again, for this particular case, the anti-join pattern seems like a round-about way of simply negating the predicates in the WHERE clause.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算
  • ¥15 java如何提取出pdf里的文字?