Можно ли преобразовать этот подзапрос в объединение? - PullRequest
1 голос
/ 17 января 2012

Я хочу заменить подзапрос объединением, если это возможно.

SELECT `fftenant_farmer`.`person_ptr_id`, `fftenant_surveyanswer`.`text_value`
FROM `fftenant_farmer`
INNER JOIN `fftenant_person` 
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_person`.`id`) 
LEFT OUTER JOIN `fftenant_surveyanswer` 
ON fftenant_surveyanswer.surveyquestion_id = 1
AND fftenant_surveyanswer.`surveyresult_id` IN (SELECT y.`surveyresult_id` FROM `fftenant_farmer_surveyresults` y WHERE y.farmer_id = `fftenant_farmer`.`person_ptr_id`)

Я пытался:

SELECT `fftenant_farmer`.`person_ptr_id`, `fftenant_surveyanswer`.`text_value`#, T5.`text_value`
FROM `fftenant_farmer`
INNER JOIN `fftenant_person` 
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_person`.`id`) 
LEFT OUTER JOIN `fftenant_farmer_surveyresults` 
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_farmer_surveyresults`.`farmer_id`) 
LEFT OUTER JOIN `fftenant_surveyanswer` 
ON (`fftenant_farmer_surveyresults`.`surveyresult_id` = `fftenant_surveyanswer`.`surveyresult_id`) 
AND fftenant_surveyanswer.surveyquestion_id = 1 

Но это дало мне по одной записи на каждого фермера на результат опроса для этого фермера. Мне нужна только одна запись на фермера, возвращаемая первым запросом.

Объединение может быть быстрее на большинстве RDBM, но настоящая причина, по которой я задал этот вопрос, заключается в том, что я просто не могу сформулировать объединение, чтобы заменить подзапрос, и я хочу знать, возможно ли это вообще.

Ответы [ 3 ]

3 голосов
/ 17 января 2012

Вы можете использовать DISTINCT или GROUP BY, как подсказывают mvds и Brilliand, но я думаю, что это ближе к замыслу разработки запроса, если вы измените последнее соединение на внутреннее, но повысите его приоритет:

SELECT farmer.person_ptr_id, surveyanswer.text_value
  FROM fftenant_farmer AS farmer
 INNER
  JOIN fftenant_person AS person
    ON person.id = farmer.person_ptr_id
  LEFT
 OUTER
  JOIN
(      fftenant_farmer_surveyresults AS farmer_surveyresults
 INNER
  JOIN fftenant_surveyanswer AS surveyanswer
    ON surveyanswer.surveyresult_id = farmer_surveyresults.surveyresult_id
   AND surveyanswer.surveyquestion_id = 1
)
    ON farmer_surveyresults.farmer_id = farmer.person_ptr_id

Вообще говоря, это приведет к тем же результатам, что и подход DISTINCT или GROUP BY, но более принципиальным, менее ad hoc способом, ИМХО.

2 голосов
/ 17 января 2012

Используйте SELECT DISTINCT или GROUP BY, чтобы удалить дублирующиеся записи.

Изменение вашей попытки как можно меньше:

SELECT DISTINCT `fftenant_farmer`.`person_ptr_id`, `fftenant_surveyanswer`.`text_value`#, T5.`text_value`
FROM `fftenant_farmer`
INNER JOIN `fftenant_person` 
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_person`.`id`) 
LEFT OUTER JOIN `fftenant_farmer_surveyresults` 
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_farmer_surveyresults`.`farmer_id`) 
LEFT OUTER JOIN `fftenant_surveyanswer` 
ON (`fftenant_farmer_surveyresults`.`surveyresult_id` = `fftenant_surveyanswer`.`surveyresult_id`) 
AND fftenant_surveyanswer.surveyquestion_id = 1
1 голос
/ 17 января 2012

настоящая причина, по которой я задал этот вопрос, заключается в том, что я просто не могу сформулировать объединение, чтобы заменить подзапрос, и я хочу знать, возможно ли это вообще

Тогда рассмотрим гораздо более простой пример, например.

SELECT * 
  FROM T1
 WHERE id IN (SELECT id FROM T2);

Это известно как semi join и при желании может быть переписано с использованием (среди прочих возможностей) JOIN с предложением SELECT в a) проекта только из «внешнего» таблица, и б) вернуть только DISTINCT строк:

SELECT DISTINCT T1.* 
  FROM T1
       JOIN T2 USING (id);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...