@pawlo00: Teraz przyszedł mi do głowy taki use case.
Jeżeli chcesz ograniczyć wyniki zapytania, to musisz subquery przesunąć z selecta do joina, bo inaczej nie dostaniesz takich samych wyników.
Załóżmy, że masz takie zapytanie
SELECT
`t`.`id`,
`t`.`agreement_number`,
`t`.`agreement_date`,
`tas`.`amount_scheduled`
FROM `transaction` AS `t`
LEFT JOIN (
SELECT
`ts`.`transaction_id`,
SUM(tsp.amount) AS `amount_scheduled`
FROM `transaction_schedule` AS `ts`
LEFT JOIN `transaction_schedule_payment` AS `tsp` ON ts.id = tsp.transaction_schedule_id
GROUP BY `ts`.`transaction_id`
) AS `tas` ON t.id = tas.transaction_id
Zapytanie wybiera:
- id
- numer umowy
- datę zawarcia umowy
- sumę wszystkich wartości z harmonogramu wpłat połączonego z dana umową
Jeżeli zostawimy jest w takiej formie w jakiej jest, czyli z left joinem, to możemy bez problemu nałożyć warunek where, który ograniczy nam wynik zapytania do transakcji, gdzie suma = 100 000.
SELECT
`t`.`id`,
`t`.`agreement_number`,
`t`.`agreement_date`,
`tas`.`amount_scheduled`
FROM `transaction` AS `t`
LEFT JOIN (
SELECT
`ts`.`transaction_id`,
SUM(tsp.amount) AS `amount_scheduled`
FROM `transaction_schedule` AS `ts`
LEFT JOIN `transaction_schedule_payment` AS `tsp` ON ts.id = tsp.transaction_schedule_id
GROUP BY `ts`.`transaction_id`
) AS `tas` ON t.id = tas.transaction_id
-- teraz dostaniemy mniej wyników
WHERE tas.amount_scheduled = 100000
Jeżeli przeniesiemy left joina do selecta, to już nie będziemy mogli ograniczyć wyników zapytania.
SELECT
`t`.`id`,
`t`.`agreement_number`,
`t`.`agreement_date`,
(SELECT SUM(tsp.amount) AS `amount_scheduled`
FROM `transaction_schedule` AS `ts`
LEFT JOIN `transaction_schedule_payment` AS `tsp` ON ts.id = tsp.transaction_schedule_id
-- dodanie tego where'a w tym miejscu nie ma sensu
-- WHERE SUM(tsp.amount) = 100000
WHERE ts.transaction_id = t.id
GROUP BY `ts`.`transaction_id`) AS `amount_scheduled`
FROM `transaction` AS `t`
-- to nie zadziała
-- WHERE tas.amount_scheduled = 100000
-- to można dodać i wynik będzie taki sam, ale having jest wolniejsze
-- HAVING amount_scheduled = 10000
Nie wiem czy nie walnąłem w tych zapytaniach jakiegoś typo, ale ideę powinieneś zrozumieć :) Jeszcze można się kłócic, że jak masz subquery w select to możesz uzyć having
, czyli taki where, ale możesz uzyc aliasu.. tylko że to jest masakrycznie wolne.
WHERE restricts the result set before returning rows and HAVING restricts the result set after bringing all the rows.