Підзапити, що повертають рядок
Досі ми обговорювали підзапити, що повертають стовпець (скалярні), тобто підзапити, що повертають єдине значення стовпця. Рядкові підзапити -це варіант підзапитів, які повертають більш за одне значення стовпця. Нижче представлено два приклади:
SELECT * FROM tl WHERE(SELECT columnl, column2 FROM t2);
SELECT * FROM tl WHERE ROW(SELECT columnl, column2 FROM t2);
Обоє ці запити істинні, якщо в таблиці t2 присутній рядок, в якому columnl = 1и column2 = 2.
Вирази (1,2) і ROW(1,2) іноді називають конструктором рядка. Ці два вирази еквівалентні. Вони цілком коректні і в інших контекстах. Наприклад, наступні два оператори семантично еквівалентні (не дивлячись на те, що тільки другою з них може бути оптимізований) :
SELECT * FROM tl WHERE(1,1);
SELECT * FROM tl WHERE columnl = 1 AND column2 = 1;
Як правило, конструктори рядка використовуються для порівняння з підзапитами, що повертають два або більшестовпців. Наприклад, представлений нижче запит виконує наступну директиву: "знайти усі рядки таблиці tl, які є також і в таблиці t2" :
SELECT columnl, column2, column3 FROM tl WHERE (columnl, column2, column3) IN
((SELECT columnl, column2, column3 FROM tl);
Підзапити в конструкції from
Підзапити дозволені і в конструкції FROM оператора SELECT. Їх синтаксис виглядає таким чином:
SELECT .. FROM (підзапит) AS ім'я ..
Конструкція AS ім'я є обов'язковим, оскільки кожна таблиця в конструкції FROM повинна мати ім'я. Усі стовпці в списку підзапиту підзапит також повинні мати унікальні імена.
Для того, щоб проілюструвати це, припустимо, що є така таблиця:
CREATE TABLE tl (si INT, s2 CHAR(5), s3 FLOAT);
Так потрібно використовувати підзапити в конструкції from для цього прикладу таблиці :
INSERT INTO tl VALUES (l,’l’, 1.0);
INSERT INTO tl VALUES (2,’2’, 2.0);
SELECT sbl, sb2, sb3 FROM (SELECT si AS sbl, s2 AS sb2, s3*2 AS sb3 FROM tl) AS sb WHERE sbl > 1;
Результат: 2, '2 ', 4.0.
А ось інший приклад. Припустимо, що ви хочете знати середнє значення сум в згрупованій таблиці. Наступний варіант працювати не буде: SELECT AVG(SUM(columnl)) FROM tl GROUP BY columnl; проте приведений нижче запит видасть потрібну інформацію:
SELECT AVG(sum_columnl)FROM (SELECT SUM(columnl) AS sum_columnl FROM tl GROUP BY columnl) AS tl;
Відмітимо, що ім'я стовпця, використовуване в підзапиті (sum_columnl) розпізнається в зовнішньому запиті.
На даний момент підзапити в конструкції FROM не можуть бути корельованими підзапитами.
Підзапит в конструкції FROM буде виконаний (тобто буде створена тимчасова таблиця) навіть для оператора EXPLAIN, тому що запити верхнього рівня потребують інформації про усі таблиці на стадії оптимізації.
Хід роботи
Написати складний запит, який виведе на екран список всіх груп, в яких навчаються тільки студенти-контрактники. Тобто побудувати запит, який буде виводити список всіх груп, але у вкладеному запиті буде перевіряти список студентів по полю "форма навчання".
<?php
$db = mysql_connect("localhost","Den","86963569");
mysql_select_db("example",$db);
$resultat = mysql_query("SELECT * FROM students WHERE teaching_form='kontrakt'",$db);
$array = mysql_fetch_array($resultat);
do
{
echo "Фамилия: ".$array['surname']."Имя: ".$array['name']."<br>Отчество: ".$array['fathername']."<br>Год рождения: ".$array['year']."<br>Група: ".$array['grupa_id']."<br>Форма навчання: ".$array['teaching_form']."<br><br>";
}
while($array = mysql_fetch_array($resultat));
?>
Вивести на екран список всіх груп, де навчається більше 10 студентів держзамовлення (результат вкладеного запиту перевіряється по умові COUNT > 10).
<?php
$db = mysql_connect("localhost","Den","86963569");
mysql_select_db("example",$db);
$resultat = mysql_query("SELECT * FROM groups WHERE count > 10",$db);
$array = mysql_fetch_array($resultat);
do
{
echo "Група: ".$array['grupa_id']."<br>Куратор: ".$array['kurator']."<br>Count: ".$array['count']."<br><br>";
}
while($array = mysql_fetch_array($resultat));
?>
Вивести на екран список всіх груп, де всі студенти молодші 18 років (результат вкладеного запиту перевіряється по полю "Year").
<?php
$db = mysql_connect("localhost","Den","86963569");
mysql_select_db("example",$db);
$resultat = mysql_query("SELECT * FROM students WHERE year > 1994",$db);
$array = mysql_fetch_array($resultat);
do
{
echo "Фамилия: ".$array['surname']."<br>Имя: ".$array['name']."<br>Отчество: ".$array['fathername']."<br>Год рождения: ".$array['year']."<br>Група: ".$array['grupa_id']."<br>Форма навчання: ".$array['teaching_form']."<br><br>";
}
while($array = mysql_fetch_array($resultat));
?>
Вивести всі записи з таблиці Students за умови, якщо в таблиці Adress існує хоча б один рядок.
<?php
$db = mysql_connect("localhost","Den","86963569");
mysql_select_db("example",$db);
$resultat = mysql_query("SELECT * FROM students WHERE EXISTS (SELECT * FROM adress)",$db);
$array = mysql_fetch_array($resultat);
do
{
echo "Фамилия: ".$array['surname']."<br>Имя: ".$array['name']."<br>Отчество: ".$array['fathername']."<br>Год рождения: ".$array['year']."<br>Група: ".$array['grupa_id']."<br>Форма навчання: ".$array['teaching_form']."<br><br>";
}
while($array = mysql_fetch_array($resultat));
?>
Вивести всі записи з таблиці Students за умови, якщо в таблиці Adress не існує жодного рядка.
<?php
$db = mysql_connect("localhost","Den","86963569");
mysql_select_db("example",$db);
$resultat = mysql_query("SELECT * FROM students WHERE NOT EXISTS (SELECT * FROM adress)",$db);
$array = mysql_fetch_array($resultat);
do
{
echo "Фамилия: ".$array['surname']."<br>Имя: ".$array['name']."<br>Отчество: ".$array['fathername']."<br>Год рождения: ".$array['year']."<br>Група: ".$array['grupa_id']."<br>Форма навчання: ".$array['teaching_form']."<br><br>";
}
while($array = mysql_fetch_array($resultat));
?>
Висновок: Навчився формувати та застосовувати багатотабличні запити SQL.
