【问题标题】:MySQL JOIN vs MySQL Shorthand JOIN(,)MySQL JOIN 与 MySQL 速记 JOIN(,)
【发布时间】:2013-01-24 15:08:59
【问题描述】:

方法一

SELECT o.*, 
       bc.*, 
       s.name  AS plan_name, 
       p.image AS course_image, 
       p.id    AS course_id, 
       p.name  AS course_name, 
       p.id, 
       p.level 
FROM   wg_guru_order o 
       JOIN wg_guru_buy_courses bc 
         ON o.id = bc.order_id 
       JOIN wg_guru_subplan s 
         ON bc.plan_id = s.id 
       JOIN wg_guru_program p 
         ON bc.course_id = p.id 
WHERE  o.status = 'Paid' 
       AND bc.userid = 451 
        OR p.catid = 26 
           AND p.published = 1

EXPLAIN 命令输出

方法二

 SELECT o.*,
       bc.*,
       s.name  AS plan_name,
       p.image AS course_image,
       p.id    AS course_id,
       p.name  AS course_name,
       p.id,
       p.level
FROM   wg_guru_order o,
       wg_guru_buy_courses bc,
       wg_guru_subplan s,
       wg_guru_program p
WHERE  o.status = 'Paid'
       AND o.id = bc.order_id
       AND bc.userid = 451
       AND bc.plan_id = s.id
       AND bc.course_id = p.id
        OR p.catid = 26
           AND p.published = 1 

EXPLAIN 命令输出

以上两个是相同的,恰好对我来说工作正常。唯一的区别是方法 1 查询使用 JOINclaues & ON 编写,方法 2 使用 JOIN 速记方法编写。

问题是方法 1 返回 3 行,方法 2 返回 1543 行。同一个查询怎么会返回不同的结果?

鉴于我只是想了解为什么会这样。我不关心结果集。我想知道的是,以两种方式编写的相同查询如何输出不同类型的结果集?

【问题讨论】:

  • 对两个查询运行 EXPLAIN 以查看实际发生的情况。
  • 好吧,我也试试
  • 这个真的很简单,他们不是同一个查询用两种不同的方式写,他们是两个不同的查询
  • 逻辑运算符优先级?
  • 试试 where (...join conditions...) 和 (...old where conditions...)

标签: mysql sql database phpmyadmin


【解决方案1】:

您的问题不是 CROSS JOIN 与 INNER JOIN,而是您的 WHERE 条件需要在适当的 OR 子句周围加上括号。

方法2应该有一个像这样的WHERE子句,相当于方法1:

WHERE ( o.id = bc.order_id
    AND bc.plan_id = s.id
    AND bc.course_id = p.id
    )
  AND ( o.status = 'Paid' AND bc.userid = 451
     OR p.catid = 26 AND p.published = 1
      )

【讨论】:

  • 请解释一下括号。没看懂
  • @Dasun 好的,所以,在您的第一个查询中,您将应用JOIN 条件,然后根据一些逻辑进行过滤。在您的第二个查询中,JOIN 条件应用于过滤器。由于您在那里有一个OR,如果满足该特定条件(p.catid = 26 AND p.published = 1),那么它使整个事情TRUE,所以JOIN 条件在这种情况下并不重要,因此返回更多结果
  • 谢谢@ypercube -- 我刚刚输入: -- 编辑 -- 我相信会看到正确的结果,请尝试这样做: WHERE ( o.status = 'Paid' AND bc.userid = 451 OR p.catid = 26 AND p.published = 1) AND (o.id = bc.order_id AND bc.plan_id = s.id AND bc.course_id = p.id)
【解决方案2】:

总是更喜欢第一个选项。

这两个选项都是标准的,但第二个选项来自较旧的 SQL-89 标准。第一个选项是新的 SQL-92 标准。较旧的标准已弃用,一些数据库开始遵循该弃用标准。例如,Sql Server 2012 放弃了对通过旧语法进行外连接的支持。 MySQL 仍然完全支持它,但您不应该真的指望它在您的应用程序的生命周期内保持这种状态。

除此之外,这些不是相同的查询。您需要在 WHERE 子句中添加一些括号来控制如何解释您的 OR 条件。这就是查询返回不同行集的原因。正如所写,就好像你的 where 子句看起来像这样:

方法一:

WHERE  (o.status = 'Paid' AND bc.userid = 451)
    OR (p.catid = 26 AND p.published = 1)

方法二:

WHERE 
   (o.status = 'Paid'
      AND o.id = bc.order_id
      AND bc.userid = 451
      AND bc.plan_id = s.id
      AND bc.course_id = p.id
   ) OR ( p.catid = 26 AND p.published = 1)

注意分组...这可能不是您想要的。我希望您的意图更像是这样:

WHERE  o.status = 'Paid'
  AND  o.id = bc.order_id
  AND  bc.course_id = p.id
  AND  bc.plan_id = s.id
  AND (bc.userid = 451 OR p.catid = 26)
  AND  p.published = 1

目前您的两个查询都不是这种方式,但我认为它更接近您真正想要做的事情。您需要在正确的位置使用括号编写查询以获得所需的结果。

【讨论】:

  • 请解释一下括号。没看懂
  • SQL-Server 和 Oracle 分别弃用了外连接旧语法(SQL-Server 的 *= 和 Oracle 的 (+))。这些从来都不是 SQL 标准的一部分。 MySQL 也没有任何这样的语法。用于内部连接的 SQL-89 语法(使用 WHERE)不推荐使用(并且可能永远不会)。
猜你喜欢
  • 1970-01-01
  • 2012-04-03
  • 2012-02-16
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 2014-07-27
  • 1970-01-01
  • 2023-03-04
相关资源
最近更新 更多