Вкладені запити, які повертають кілька рядків
У попередньому були розглянуті запити, де вкладений запит повертає єдине значення. Якщо вкладений запит повертає кілька рядків, СУБД MySQL повертаєпомилку 1242 - вкладений запит повертає більш ніж один рядок (приклад).
SELECT name FROM catalogs
WHERE id_catalog = (SELECT id_catalog FROM products);
ERROR 1242: Subquery returns more than 1 row
Оператор IN
Для того щоб вибрати рядки з таблиці catalogs, у яких первинний ключ id_catalogзбігається з одним зі значень, що повертаються вкладеним запитом, слідскористатися конструкцією in.
Приклад
SELECT name FROM catalogs
WHERE id_catalog IN (SELECT id_catalog FROM products
GROUP BY id catalog);
name
Процесори
Материнські плати
Відеоадаптери
Жорсткі диски
Оперативна пам’ять
Запит, представлений в прикладі, аналогічний запиту
SELECT name FROM catalogs WHERE id_catalog IN (1,2,3,4,5);
name
Процесори
Материнські плати
Відеоадаптери
Жорсткі диски
Оперативна пам’ять
Для того щоб повернути рядки, які відсутні в результуючій таблиці, яка повертається вкладеним запитом, слід скористатися оператором NOT in, представленим у прикладі
SELECT name FROM catalogs
WHERE id catalog NOT IN (SELECT DISTINCT id_catalog
FROM products WHERE id_catalog<3);
name
Відеоадаптери
Жорсткі диски
Оперативна пам’ять
Оператор ANY (SOME)
Конструкція in дозволяє здійснити пошук величини в списку і висловлює логікузапиту, поданого у прикладі. Однак на місці оператора в цьому запиті можестояти інший оператор порівняння (приклад). Для цього використовується оператор any
Зауваження
Оператор any має синонім some, проте краще використовувати саме any.
SELECT id_catalog, name FROM catalogs
WHERE id_catalog > ANY (SELECT id_catalog FROM products);
id_catalog name
2 Материнскі плати
3 Відеоадаптери
4 Жорсткі диски
5 Оперативна пам’ять
Ключове слово ANY може застосовуватися для порівняння значень звикористанням одного з шести операторів порівняння ("=", "<>", "<", "<=", ">",">="). Перевіряється значення id_catalog по черзі порівнюється з кожнимелементом, який повертає вкладений запит. Якщо хоча б одне з порівняньповертає 1 (істина), рядок виводиться запитом. У прикладі відбувається порівняння значень первинного ключа id_catalog (1, 2, 3, 4, 5), які присутні втаблиці catalogs, зі значеннями поля id_catalog (1, 2, 3, 4, 5) з таблиці products.Значення id_catalog = 1 не задовольняє ні одній умові:
1> 1 - 0 (брехня)
1> 2 - 0 (брехня)
1> 3 - 0 (брехня)
1> 4 - 0 (брехня)
1> 5 - 0 (брехня)
Тому в результати цей рядок не потрапляє, в той же час всі інші цифризадовольняють хоча б одній умові і потрапляють в результуючу таблицю.
Тобто запит вигляду
"Where X> ANY (SELECT Y. ..)"
Можна інтерпретувати як "де X більше хоча б одного обраного Y".
А запит вигляду
"Where x <any (select y. ..)"
Слід читати "де X менше, ніж будь-який обраний Y. .."
Запит, поданий у прикладі, повертає ім'я та прізвище клієнтів з таблиці users, які зробили хоча б одну покупку.
Приклад
SELECT name, surname FROM users
WHERE id_user = ANY (SELECT id_user FROM orders);
name surname
Олександр Іванов
Ігор Сімідянов
Олександр Корнеев
На практиці порівняння з використанням ключового слова any може призводитидо помилок, які важко виявити, особливо коли застосовується операторпорівняння "не дорівнює" ("<>" або "!="). Так, якщо буде потрібно повернутисписок клієнтів, не здійснювали жодної покупки, виникне спокуса замінитиоператор рівності "=" (попередній приклад) на оператор нерівності "<>" (приклад).
SELECT name, surname FROM users
WHERE id_user <> any (SELECT id_user FROM orders);
name surname
Олександр Іванов
Сергій Лосєв
Ігор Сімідянов
Максим Кузнєцов
Анатолій Поганець
Олександр Корнєєв
Результатом є повний список покупців як здійснювали, так і не здійснювалипокупок, оскільки значення id_user порівнюється з кожним значенням, якеповертає вкладений запит. Серед цих значень завжди знайдеться число, яке недорівнюватиме поточному значенню id_user. Вирішити цю задачу можна за допомогою операторів exists і not exists, які розглянуті в далі.