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条)

报告相同问题?

悬赏问题

  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图