РезюмеMySQL комплекса Полусоединение без группы по
Я ищу Полусоединение (МОГ) запрос, который выбирает количество клиентов и соединяет их самые последние данные из других таблиц.
В более позднее время, я хочу непосредственно добавлять условия к концу запроса: WHERE c.id IN (1,2,3)
Проблема
Насколько я знаю, мое требование исключает GROUP BY
:
SELECT * FROM customer c
LEFT JOIN customer_address ca ON ca.customer_id = c.id
GROUP BY c.id
# PROBLEM: Cannot append conditions *after* GROUP BY!
С большинством попыток, основанных на подзапросах, моя проблема такая же.
В качестве дополнительной задачи я не могу строго использовать полусоединение, поскольку допускаю, по крайней мере, два типа телефонных номеров (мобильных и стационарных), которые поступают из одной таблицы. Таким образом, из телефонной таблицы я могу присоединить несколько записей на одного клиента, т. Е. Это больше не является полусоединением. Мое настоящее решение ниже иллюстрирует это.
Вопросы
EXPLAIN
результат в нижней части выглядит производительным для меня. Я прав? Каждый из подзапросов выполняется только один раз? Обновление: Похоже, чтоDEPENDENT SUBQUERY
выполняется один раз для каждой строки во внешнем запросе. Было бы здорово, если бы мы могли избежать этого.- Есть ли лучшее решение для того, что я делаю?
DDLS
DROP TABLE IF EXISTS customer;
CREATE TABLE `customer` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
);
DROP TABLE IF EXISTS customer_address;
CREATE TABLE `customer_address` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`customer_id` bigint(20) unsigned NOT NULL,
`street` varchar(85) DEFAULT NULL,
`house_number` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
);
DROP TABLE IF EXISTS customer_phone;
CREATE TABLE `customer_phone` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`customer_id` bigint(20) unsigned NOT NULL,
`phone` varchar(32) DEFAULT NULL,
`type` tinyint(3) unsigned NOT NULL COMMENT '1=mobile,2=landline',
PRIMARY KEY (`id`)
);
insert ignore customer values (1);
insert ignore customer_address values (1, 1, "OldStreet", 1),(2, 1, "NewStreet", 1);
insert ignore customer_phone values (1, 1, "12345-M", 1),(2, 1, "12345-L-Old", 2),(3, 1, "12345-L-New", 2);
SELECT * FROM customer;
+----+
| id |
+----+
| 1 |
+----+
SELECT * FROM customer_address;
+----+-------------+-----------+--------------+
| id | customer_id | street | house_number |
+----+-------------+-----------+--------------+
| 1 | 1 | OldStreet | 1 |
| 2 | 1 | NewStreet | 1 |
+----+-------------+-----------+--------------+
SELECT * FROM customer_phone;
+----+-------------+-------------+------+
| id | customer_id | phone | type |
+----+-------------+-------------+------+
| 1 | 1 | 12345-M | 1 |
| 2 | 1 | 12345-L-Old | 2 |
| 3 | 1 | 12345-L-New | 2 |
+----+-------------+-------------+------+
Решение до сих пор
SELECT *
FROM customer c
# Join the most recent address
LEFT JOIN customer_address ca ON ca.id = (SELECT MAX(ca.id) FROM customer_address ca WHERE ca.customer_id = c.id)
# Join the most recent mobile phone number
LEFT JOIN customer_phone cphm ON cphm.id = (SELECT MAX(cphm.id) FROM customer_phone cphm WHERE cphm.customer_id = c.id AND cphm.`type` = 1)
# Join the most recent landline phone number
LEFT JOIN customer_phone cphl ON cphl.id = (SELECT MAX(cphl.id) FROM customer_phone cphl WHERE cphl.customer_id = c.id AND cphl.`type` = 2)
# Yay conditions appended at the end
WHERE c.id IN (1,2,3)
Fiddle
Эта скрипка дает соответствующий набор результатов, используя данную Soluti на. См. Мои вопросы выше.
http://sqlfiddle.com/#!9/98c57/3
Параметр 'where' предваряет «группа». Что так сложно в использовании правильного синтаксиса? Непонятно, что вы пытаетесь сделать. Хорошим способом объяснить проблему является использование выборочных данных и желаемых результатов. И, наконец, в чем ваш вопрос? –
Трудность состоит в том, что запрос должен быть помещен в константу строки без условий. Условия затем добавляются в различные варианты использования. Я не хочу вырезать запрос в шпагате, чтобы условия были в правильном месте. До сих пор мы используем простое приложение для всех наших запросов, и я не хочу отклоняться от этого. – Timo
Попробуйте добавить HAVING вместо WHERE. Надеюсь, оптимизатор разобратся. Похоже, что у вас есть кусочек рамок, но все же. – LoztInSpace