【问题标题】:Problems with left outer joins左外连接的问题
【发布时间】:2011-07-21 19:20:17
【问题描述】:

我很确定我需要在我的表上进行左外连接,但我不确定这是否 100% 正确或在 mySQL 中编写它们的语法。

我写了这个查询:

select m.mechanic_id, 
   m.mechanic_name, 
   m.city, 
   m.state, 
   count(mr.mechanic_id) as num_ratings, 
   round(avg(mr.quality_id),2) quality_rating
   round(avg(mr.friendly_id),2) friendly_rating,
   round(avg(mr.professional_id),2) professional_rating
from mechanic m, mechanic_rating mr, rating r
where m.mechanic_id in (1)
and m.mechanic_id = mr.mechanic_id
and mr.quality_id = r.rating_id(+) <-- these cause issues
and mr.friendly_id = r.rating_id(+) <-- these cause issues
and mr.professional_id = r.rating_id(+) <-- these cause issues
group by mechanic_id

(+) 是在 oracle 中进行外连接的一种方法,我不确定如何在此查询中手动写出外连接。我什至不确定我是否将它们放在正确的列上。

我的表结构是这样的

机械表

|mechanic_id|mechanic_name|city|state|zip|
|PK         |

评分表

|rating_id|rating  |
|1        |terrible|
|2        |bad     |
etc.

Mechanic_Rating 表

|mechanic_rating_id|mechanic_id|quality_id|friendly_id|professional_id|
|unique auto inc   |FK         |

quality_id、friendly_id 和 Professional_id 都应该是评级表中 rating_id 的外键。

如果我从查询中删除 (+),我得到的结果为零,所以我认为问题在于我需要进行左外连接。如果您需要更多信息,请告诉我。

【问题讨论】:

    标签: mysql database join


    【解决方案1】:

    您需要学习和使用 ANSI-92 标准语法来执行连接谓词。使用 ANSI-92,您的查询将被写为

     select m.mechanic_id,  m.mechanic_name, m.city,
         m.state, count(mr.mechanic_id) num_ratings, 
         round(avg(mr.quality_id),2) quality_rating   
         round(avg(mr.friendly_id),2) friendly_rating,   
         round(avg(mr.professional_id),2) professional_rating
    from mechanic m
       Left Join mechanic_rating mr
           On mr.mechanic_id = m.mechanic_id
       Left Join rating r 
           On r.rating_id = mr.quality_id
               And r.rating_id = mr.friendly_id
               And r.rating_id = mr.friendly_id 
     where m.mechanic_id in (1)
     group by mechanic_id
    

    注意:(1) 指的是什么?您是否试图将其限制为
    其中 m.mechanic_id = 1 ?

    【讨论】:

    • 我在我的应用程序中使用了一个包含 1 个或多个 id 的变量。我只是用“1”来测试我的查询。
    • 我假设这个变量是一个表变量??否则,您不需要进行 Group By ...
    【解决方案2】:

    这应该可以解决您与 (+); 相关的问题;使用 LEFT OUTER JOIN 意味着即使右表中没有元素,左表中的所有内容都将被包括在内。同样,右侧所有内容的列(如果没有匹配项)将为 NULL。

    select m.mechanic_id, 
       m.mechanic_name, 
       m.city, 
       m.state, 
       count(mr.mechanic_id) as num_ratings, 
       round(avg(mr.quality_id),2) quality_rating
       round(avg(mr.friendly_id),2) friendly_rating,
       round(avg(mr.professional_id),2) professional_rating
    FROM mechanic m LEFT OUTER JOIN mechanic_rating mr ON(m.mechanic_id = mr.mechanic_id) 
    LEFT OUTER JOIN rating r ON(mr.quality_id = r.rating_id AND 
    mr.friendly_id = r.rating_id AND mr.professional_id = r.rating_id) 
    WHERE m.mechanic_id in (1) GROUP BY mechanic_id
    

    【讨论】:

    • 我认为您将 LEFT OUTER JOINLEFT JOIN 混淆了。
    • 你的两个查询的结果是一样的。外在的不是隐含的吗?
    • 如果我没有记错(我可能是),我认为LEFT JOIN 就是您在上面描述的内容,而LEFT OUTER JOIN 只是左表中没有的那些一场比赛。
    • 左连接 = 左外连接;如果指定了 LEFT,则隐含 OUTTER。同样,如果未指定 LEFT,则 JOIN = INNER JOIN。
    【解决方案3】:

    您的评分是独立且正交的,对吗?您需要在不同的别名中使用相同的评级表:

    from mechanic m
       Left Join mechanic_rating mr
           On mr.mechanic_id = m.mechanic_id
       Left Join rating r_quality
           On r_quality.rating_id = mr.quality_id
       Left Join rating r_friendly
           On r_friendly.rating_id = mr.friendly_id
       Left Join rating r_professional
           On r_professional.rating_id = mr.professional_id
    

    像您所做的那样将它们全部组合起来将简单地过滤掉独立评级不完全相同的所有行,这可能是影响您看到的结果的另一件事。

    虽然外键是同一个表,但每个键都是独立的,因此您需要表的“角色”才能发挥作用。

    但是,由于您没有在选择列表中使用任何评级列,因此您实际上可以完全不使用它们:

    select m.mechanic_id, 
       m.mechanic_name, 
       m.city, 
       m.state, 
       count(mr.mechanic_id) as num_ratings, 
       round(avg(mr.quality_id),2) quality_rating
       round(avg(mr.friendly_id),2) friendly_rating,
       round(avg(mr.professional_id),2) professional_rating
    from mechanic m, mechanic_rating mr
    where m.mechanic_id in (1)
    and m.mechanic_id = mr.mechanic_id
    group by mechanic_id
    

    请注意,您也可以修复旧式连接:

    from mechanic m, mechanic_rating mr, rating r_quality, rating r_friendly, rating r_professional
    where m.mechanic_id in (1)
    and m.mechanic_id = mr.mechanic_id
    and mr.quality_id = r_quality.rating_id(+)
    and mr.friendly_id = r_friendly.rating_id(+)
    and mr.professional_id = r_professional.rating_id(+)
    group by mechanic_id
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-31
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多