MySQL « Проблема с count() и Left Join в MySQL
Почему count в sql-запросе с left outer join не возвращает 0, если не находит строки подходящие под условие?
Из мануала MySQL
// COUNT() returns 0 if there were no matching rows
/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .sql.geshi_code {font-family:monospace;} .sql.geshi_code .imp {font-weight: bold; color: red;} .sql.geshi_code .kw1 {color: #993333; font-weight: bold;} .sql.geshi_code .co1 {color: #808080; font-style: italic;} .sql.geshi_code .co2 {color: #808080; font-style: italic;} .sql.geshi_code .coMULTI {color: #808080; font-style: italic;} .sql.geshi_code .es0 {color: #000099; font-weight: bold;} .sql.geshi_code .br0 {color: #66cc66;} .sql.geshi_code .sy0 {color: #66cc66;} .sql.geshi_code .st0 {color: #ff0000;} .sql.geshi_code .nu0 {color: #cc66cc;} .sql.geshi_code span.xtra { display:block; }
SELECT t.`id`, t.`name`, COUNT(t2.`id`) AS `cat_count`
FROM `ch_razdel2` AS t
LEFT JOIN `ch_razdel2_info` AS t2 ON t.`id` = t2.`id_cat`
WHERE <…>
GROUP BY t.`id`
ORDER BY t.`name`
Таблица t (разделы)
id | name
Таблица t2 (позиции, относящиеся к разделам)
id | id_cat | text | result | time1 | time2
Т.е. этим запросом я могу получить только список разделов с количеством позиций, если они не пустые.
Из мануала MySQL
// COUNT() returns 0 if there were no matching rows
/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .sql.geshi_code {font-family:monospace;} .sql.geshi_code .imp {font-weight: bold; color: red;} .sql.geshi_code .kw1 {color: #993333; font-weight: bold;} .sql.geshi_code .co1 {color: #808080; font-style: italic;} .sql.geshi_code .co2 {color: #808080; font-style: italic;} .sql.geshi_code .coMULTI {color: #808080; font-style: italic;} .sql.geshi_code .es0 {color: #000099; font-weight: bold;} .sql.geshi_code .br0 {color: #66cc66;} .sql.geshi_code .sy0 {color: #66cc66;} .sql.geshi_code .st0 {color: #ff0000;} .sql.geshi_code .nu0 {color: #cc66cc;} .sql.geshi_code span.xtra { display:block; }
SELECT t.`id`, t.`name`, COUNT(t2.`id`) AS `cat_count`
FROM `ch_razdel2` AS t
LEFT JOIN `ch_razdel2_info` AS t2 ON t.`id` = t2.`id_cat`
WHERE <…>
GROUP BY t.`id`
ORDER BY t.`name`
Таблица t (разделы)
id | name
Таблица t2 (позиции, относящиеся к разделам)
id | id_cat | text | result | time1 | time2
Т.е. этим запросом я могу получить только список разделов с количеством позиций, если они не пустые.
1 ответов
Для оптимизации можно попробовать сначала наложить фильтры на большую таблицу, и только после этого соединять ее.
SELECT t.`id`, t.`name`, COUNT(t2.`id`) AS `cat_count`
FROM `ch_razdel2` AS t
LEFT JOIN (
select `id`, `id_cat`
from `ch_razdel2_info`
where `result` = 0 AND `time1` < {current_time} AND `time2` > {current_time}
) AS t2
ON t.`id` = t2.`id_cat`
GROUP BY t.`id`
ORDER BY t.`name`
WHERE t2.`result` = 0 AND t2.`time1` < {current_time}
AND t2.`time2` > {current_time}
"превращают" (не совсем корректный термин) LEFT JOIN в INNER - если в t2 нет записей соответсвующих условию в ON, все поля у t2 - NULL, записи будут выкинуты в WHERE . Если я правильно понял вопрос, то надо просто перенести условия, касающиеся t2 из WHERE в ON:
SELECT t.`id`, t.`name`, COUNT(t2.`id`) AS `cat_count`
FROM `ch_razdel2` AS t
LEFT JOIN `ch_razdel2_info` AS t2 (ON t.`id` = t2.`id_cat` AND
t2.`result` = 0 AND t2.`time1` < {current_time}
AND t2.`time2` > {current_time} )
GROUP BY t.`id`
ORDER BY t.`name`