Проблемы с левыми внешними соединениями - PullRequest
1 голос
/ 24 марта 2011

Я почти уверен, что мне нужно выполнять левые внешние объединения в моих таблицах, но я не уверен, верно ли это на 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 table

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

quality_id, friendly_id и professional_id должны быть внешними ключами для rating_id в таблице рейтинга.

Если я уберу (+) из своего запроса, я получу ноль результатов, поэтому я думаю, что проблема в том, что мне нужно делать левые внешние соединения. Дайте мне знать, если вам нужна дополнительная информация.

Ответы [ 3 ]

2 голосов
/ 24 марта 2011

Вам необходимо изучить и использовать стандартный синтаксис ANSI-92 для выполнения предикатов Join.Используя 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 голос
/ 24 марта 2011

Ваши оценки независимы и ортогональны, верно? Вы должны иметь одну и ту же таблицу рейтинга, используемую в разных псевдонимах:

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
1 голос
/ 24 марта 2011

Это должно решить вашу проблему с (+);использование 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...