【问题标题】:"Combine" FULL OUTER JOIN and NOT IN?“组合”完全外连接而不是内连接?
【发布时间】:2017-09-12 23:30:20
【问题描述】:

我有两张桌子:

+-----------------------+
| Tables_in_my_database |
+-----------------------+
| orders                | 
| orderTaken            | 
+-----------------------+

订单中有属性

orderId, orderName, isClosed and orderCreationTime. 

在orderTaken中,有属性

userId, orderId and orderStatus. 

我们说什么时候

orderStatus = 1 --> the customer has taken the order
orderStatus = 2 --> the order has been shipped
orderStatus = 3 --> the order is completed
orderStatus = 4 --> the order is canceled
orderStatus = 5 --> the order has an exception

基本上我的项目的机制是这样运行的:具有唯一 userId 的用户将能够从网页上接受订单,其中每个订单也有自己唯一的 orderId。取完后,orderTaken 表会记录 userId、orderId 并初始设置 orderStatus = 1。然后店铺根据各种情况更新 orderStatus。一旦商店更新了 isClosed = 1,那么无论用户是否接受了这个订单,都不会显示(没有意义,但它只是查询中的 isClosed == 0)。

现在,我想构建一个网页,显示用户尚未接受的新订单(应该是他们的 orderIds 未记录在该用户的 userId 下的 orderTaken 表中的订单),以及用户已经使用 orderStatus 显示的订单但 orderStatus 不是 4 或 5,按 orderCreationTime DESC 分组(是的,如果我没有 orderTakenTime 但让我们保持这种方式可能没有意义),例如:

OrderId 4
Order Name: PetPikachu
orderStatus = 1
CreationTime: 5am

OrderId 3
Order Name: A truck of hamsters
orderStatus = 3
CreationTime: 4am

OrderId 2
New order
Order Name: Macbuk bull
CreationTime: 3am

OrderId 1
Order Name: Jay Chou's Album
orderStatus = 2
CreationTime: 2am

我根据所学知识编写了这个查询:

SELECT * FROM orders A WHERE A.isClosed == '0' FULL OUTER JOIN orderTaken B  WHERE B.userId = '4' AND (B.orderStatus<>'4' OR B.orderStatus<>'5') ORDER BY A.orderCreationTime DESC;

显然这个查询不起作用,但我害怕有一个

ON A.orderId = B.orderId

从那时起,返回的表将消除 orderId 未记录在 orderTaken B 中的新订单。我还尝试了 NOT IN 子句,如

SELECT * FROM orders A WHERE A.isClosed = '0' AND A.orderId NOT IN (SELECT orderId FROM orderTaken B WHERE B.userId = '$userId' AND (B.orderStatus='4' OR B.orderStatus='5')) ORDER BY creationTime DESC;

此查询有效,但返回的表中没有 orderTaken B 的字段 orderStatus。我正在考虑在此查询之后添加另一个 JOIN orderTaken B 子句以从 B 获取字段,但我认为这不是编写查询的好方法。

我只是想将“NOT IN”和“FULL JOIN”结合起来。有人可以帮帮我吗?谢谢!

【问题讨论】:

    标签: mysql join where notin full-outer-join


    【解决方案1】:

    就像@terje-d 说的,你需要的是LEFT JOIN。使用原始表名对其进行了更新,并修复了 $userId 过滤器。

    • 适用于所有未结订单和未完成订单。
       SELECT o.`orderId`, 
              o.`orderName`,
              ot.`orderStatus`,
              o.`orderCreationTime`
         FROM orders o 
    LEFT JOIN orderTaken ot
           ON o.orderId = ot.orderId
        WHERE o.isClosed = 0
          AND (
                ot.orderId IS NULL
             OR ot.orderStatus NOT IN (4,5)
          )
     ORDER BY o.`orderCreationTime` DESC
    
    • 针对特定用户的所有未结订单和未完成订单
       SELECT o.`orderId`, 
              o.`orderName`,
              ot.`orderStatus`,
              o.`orderCreationTime`
         FROM orders o 
    LEFT JOIN orderTaken ot
           ON o.orderId = ot.orderId
        WHERE o.isClosed = 0
          AND ( ot.orderStatus IS NULL
             OR (
                    ot.user_id = ?
                AND ot.orderStatus NOT IN (4,5)
             )
          )
     ORDER BY o.`orderCreationTime` DESC
    

    【讨论】:

    • 是的,Jben 感谢您改进的答案!是的 Terje 给出了错误的表名,但逻辑是正确的,您的回答只是让它 110% 完美!并感谢您对选择特定用户的提示! :D 你真是太棒了!
    • 嗨@j-bin 实际上我认为这段代码可能有错误?今天我尝试在多个用户同时接受订单的情况下测试这个查询。我使用店主帐户创建了一个新订单,然后运行此查询我可以看到这个新订单在每个用户的页面上,但是在其中一个用户接单后,说 userId=3 的那个,然后是其他用户如 userId=2or4 将不会再看到此订单,但是此订单继续显示在 userId=3 的页面上,并且状态显示正确。我试图通过采用 ot.user_id = 来修改代码?到 where 子句并使它像:
    • WHERE o.isClosed = 0 AND ot.user_id = 2/4 AND ( (ot.orderStatus IS NULL) OR (ot.orderStatus NOT IN (4,5))),但是这仍然返回一个空数组。我还尝试将此 user_id 限制放到任何其他地方,但没有运气。你还能看一下吗,我真的很感激! :D
    • 我猜是因为一旦有人从这个orderId下了一个订单,那么这个orderId就会被记录在ot表中,所以如果我们仍然让它“ON o.orderId = ot.orderId”虽然我们放了一个 ot.orderId IS NULL 或 ot.orderStatus IS NULL 因为它不再是 NULL 所以不会有结果?
    • 如果只有一个用户接单,这个查询的测试就完美了,但是在这个用户接单之后,如果我们让userId等于其他用户的userId,那么这将返回一个空设置
    【解决方案2】:

    您似乎希望在orders 中找到未分配给用户的记录(ieorderTaken 中没有相关记录)以及分配给用户的记录用户,但 orderStatus 不是 4 或 5。

    然后不需要完整的外部连接,因为orderTaken 中没有记录,而orders 中没有相关记录。 Left inner join 可用于查找来自orders 的所有记录,on 子句将包含来自orderTaken 的相关记录的数据,然后where 子句可以过滤掉其他用户的订单,或者其中 orderStatus 为 4 或 5:

    SELECT o.*, ot.userID, ot.orderStatus
    FROM orders o
    LEFT JOIN orderTaken ot
    ON ot.orderID = o.orderID
    WHERE o.isClosed = 0
    AND (ot.userID IS NULL OR ot.userID = $userID AND ot.orderStatus NOT IN (4,5))
    ORDER BY o.creationTime DESC
    

    【讨论】:

    • 谢谢泰尔杰!这正是我想要的!我正在考虑使用 LEFT JOIN,但我只是不知道“IS NULL”子句。这是我从你那里学到的关键一件事。再次感谢您解决我的问题! :D
    • 我现在已经更正了表名(orderTaken,拼错为 orderStatus)。
    • 这使它更精确。再次感谢 Terje!
    • 嗨 Terje D. 你能在 j-bin 的回答下看看我的 cmets 吗?在其中一个用户接受订单后,您提供的查询还将为其他用户返回一个空集... :( 假设在 userID=3 的用户接受订单后,如果我使用 userId=4 运行您的查询,那么它将返回一个空集。
    • 您希望为多个用户(例如 2 和 3)而不是当前的 (4) 接受的订单显示什么?您是只需要一行显示用户 4 未接受订单,还是需要为每个接受订单的用户一行显示每个用户的相关 orderStatus?
    猜你喜欢
    • 2017-03-25
    • 2014-09-23
    • 1970-01-01
    • 1970-01-01
    • 2016-12-19
    • 2020-04-27
    • 2017-06-09
    • 1970-01-01
    • 2012-01-06
    相关资源
    最近更新 更多