DQL - Еще одна подгруппа языка SQL которая состоит из всего одного слова SELECT.
Но, не спешим радоваться, в нем деталей примерно как во всех прошлых командах вместе взятых.
Самый простой вариант запроса выглядит так:
SELECT *
FROM book;Выбрать все столбцы и все колонки из таблицы book.
Можно выбрать только часть столбцов:
SELECT title, page_count
FROM book;Теперь мы выбираем только колонки title и page_count.
На самом деле SQL является еще и калькулятором, поэтому мы можем получить не только значение, но и вычисления:
SELECT title, page_count / 2
FROM book;Тут мы разделили кол-во страниц в книге на 2.
Вообще SQL можно использовать как калькулятор и без данных. Это довольно странно, но можно.
SELECT 40 + 2;В реальности, доставать все данные из таблицы практически никогда не нужно. Обычно мы вытаскиваем только необходимую нам информацию.
SELECT id, name, author
FROM book
WHERE author = "King";
SELECT id, name
FROM book
WHERE genre IN ("Action", "Comedy");
SELECT id, name
FROM book
WHERE page_count BETWEEN 100 AND 200;В первом запросе мы вытаскиваем все книги у которых в поле автор записано King.
Во втором, все книги у которых жанр это Action или Comedy.
В третьем все книги у которых кол-во страниц от 100 до 200.
Естественно все условия можно комбинировать через
ORиAND
Для того что бы назвать результаты ваших запросов, можно использовать ключевое слово as. Это нам еще в дальнейшем
понадобится.
SELECT title, page_count / 2 as sheets
FROM book;Тут sheets это метка
Метки часто называют словом псевдоним
Ключевое слово DISTINCT необходимо, что бы получить только уникальные значения для какого либо поля.
SELECT DISTINCT publisher
FROM book;Что бы получить список уникальных издателей для всех книг.
Часто нам необходимо данные отсортировать на этапе получения.
Для этого нам поможет ORDER BY:
SELECT title, publisher_id
FROM book
ORDER BY title;Что можно делать с сортировкой:
- Указывать порядок (прямой или обратный)
- Указывать более одного поля для сортировки
Примеры:
Указываем порядок:
SELECT title, publisher_id
FROM book
ORDER BY title ASC;
SELECT title, publisher_id
FROM book
ORDER BY title DESC;Указываем несколько полей для сортировки.
SELECT title, publisher_id
FROM book
ORDER BY title, publisher DESC;
SELECT title, publisher_id
FROM book
ORDER BY title DESC, publisher ASC;Так же мы можем ограничить кол-во получаемых результатов. Зачем это делать? А что если под наше условие подходит миллиард записей? Сможем ли мы их все обработать? Думаю что нет. Но мы всегда можем указать необходимую нам сортировку, и только после этого указать лимит в каком-то небольшом кол-ве данных.
SELECT *
FROM publisher
LIMIT 10;Вернет только первые 10 зачений.
SELECT *
FROM publisher
LIMIT 10 OFFSET 10;Вернет значения с 11-ого по 20-е. OFFSET - сдвиг по данным.
Индекс в базе данных — это специальная структура данных, которая улучшает скорость поиска данных в таблице. Индексы создаются на основе одного или нескольких столбцов таблицы и позволяют быстро находить строки, удовлетворяющие определенным условиям.
Представьте индекс как оглавление книги: вместо того чтобы просматривать всю книгу, чтобы найти нужную информацию, вы можете просто заглянуть в оглавление и быстро перейти к нужной странице.
Индексы бывают разных типов, разные типы используются часто для разных типов данных. Вникать в детали нам пока нет никакой необходимости, но я их перечислю.
Это самый распространенный тип индекса. B-Tree индексы используются по умолчанию при создании индекса и подходят для большинства операций поиска и сортировки. (Работают на бинарном поиске)
Эти индексы полезны для операций равенства. Они не поддерживают диапазонные запросы и не так универсальны, как B-Tree индексы.
Используются для более сложных типов данных, таких как геометрические и полнотекстовые поиски.
Эти индексы эффективны для поиска в больших текстовых полях и массивных данных.
Индексы, которые используются для очень больших таблиц, где данные имеют четкий порядок. Они занимают меньше места и подходят для диапазонных запросов.
CREATE INDEX index_name ON table_name (column_name);Пример:
CREATE INDEX idx_users_last_name ON users (last_name);Этот индекс ускорит запросы, которые фильтруют или сортируют данные по last_name.
Уникальные индексы обеспечивают уникальность значений в столбце.
CREATE UNIQUE INDEX index_name ON table_name (column_name);Пример:
CREATE UNIQUE INDEX idx_unique_email ON users (email);Да, индекс не всегда привязан к одному полю
CREATE INDEX index_name ON table_name (column1, column2);Пример:
CREATE INDEX idx_users_last_first_name ON users (last_name, first_name);Этот индекс будет полезен для запросов, использующих оба столбца last_name и first_name.
Ничего дополнительного делать с индексом не нужно, если он есть, он уже будет влиять на работу системы.
SELECT *
FROM users
WHERE last_name = 'Smith';Если у нас есть индекс на столбце last_name, то этот запрос выполнится значительно быстрее.
SELECT *
FROM users
ORDER BY last_name;Индекс на last_name также ускорит выполнение этого запроса.
Чтобы увидеть все индексы в таблице, можно использовать следующую команду:
\d table_nameЕсли индекс больше не нужен, его можно удалить:
DROP INDEX index_name;Пример:
DROP INDEX idx_users_last_name;А если все так хорошо и быстро, почему бы нам не создать индексы вообще на все поля и все будет работать быстрее?
И да и нет.
Если бы у нас были только операции чтения, то это было бы идеальное решение. Но у нас есть и другие операции.
Представте книгу у которой есть оглавление (по сути та же индексация). Пока мы можем только читать книгу, проблем нет, добавили несколько страниц в начале, чем упростили жизнь.
Но теперь представте, что вы в эту книгу начинаете дописывать/удалять/изменять страницы или целые главы.
Для каждой такой операции, оглавление придется переписывать заново.
Если в таблицу часто производится запись/изменение/удаление, то индекс только замедлил работу базы! А он еще и место занимает! Поэтому всегда нужно очень аккуратно относиться к индексам, это очень хороший инструмент, который легко может все сломать
В SQL встроено довольно-таки большое количество функций которыми мы можем пользоваться и часть из них будет
использована в дальнейшем для агрегации данных, давайте с некоторыми из них познакомимся.
Таблица истинности для SQL, учитывающая NULL, отличается от обычной таблицы истинности, так как NULL в SQL
представляет неопределенное значение. В операциях сравнения и логических операциях NULL ведет себя особым образом.
Вот таблица истинности для SQL с учетом NULL:
| A | B | A AND B | A OR B | NOT A |
|---|---|---|---|---|
| TRUE | TRUE | TRUE | TRUE | FALSE |
| TRUE | FALSE | FALSE | TRUE | FALSE |
| TRUE | NULL | NULL | TRUE | FALSE |
| FALSE | TRUE | FALSE | TRUE | TRUE |
| FALSE | FALSE | FALSE | FALSE | TRUE |
| FALSE | NULL | FALSE | NULL | TRUE |
| NULL | TRUE | NULL | TRUE | NULL |
| NULL | FALSE | FALSE | NULL | NULL |
| NULL | NULL | NULL | NULL | NULL |
| A | B | A = B | A <> B | A < B | A > B | A <= B | A >= B |
|---|---|---|---|---|---|---|---|
| TRUE | TRUE | TRUE | FALSE | FALSE | FALSE | TRUE | TRUE |
| TRUE | FALSE | FALSE | TRUE | FALSE | TRUE | FALSE | TRUE |
| TRUE | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| FALSE | TRUE | FALSE | TRUE | TRUE | FALSE | TRUE | FALSE |
| FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | TRUE | TRUE |
| FALSE | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| NULL | TRUE | NULL | NULL | NULL | NULL | NULL | NULL |
| NULL | FALSE | NULL | NULL | NULL | NULL | NULL | NULL |
| NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
-
Логические операторы:
A AND BвернетTRUE, только если оба значенияTRUE.A OR BвернетTRUE, если хотя бы одно значениеTRUE.NOT Aвернет противоположное значение, еслиAнеNULL.
-
Операторы сравнения:
- Любое сравнение с
NULLвсегда возвращаетNULL(неопределенное).
- Любое сравнение с
Эти правила делают работу с NULL в SQL специфической, и при работе с данными нужно учитывать, что NULL не
эквивалентен ни TRUE, ни FALSE, а представляет собой третье состояние, которое требует особого внимания при
логических и сравнительных операциях.
Прежде чем мы перейдем к математическим функциям, давайте рассмотрим основные математические операции в SQL:
- Сложение (+): складывает два числа.
SELECT 5 + 3 AS sum_result; -- Результат: 8
- Вычитание (-): вычитает одно число из другого.
SELECT 5 - 3 AS subtract_result; -- Результат: 2
- Умножение (*): умножает два числа.
SELECT 5 * 3 AS multiply_result; -- Результат: 15
- Деление (/): делит одно число на другое.
SELECT 6 / 3 AS divide_result; -- Результат: 2
- Остаток от деления (%): возвращает остаток от деления одного числа на другое.
SELECT 5 % 3 AS mod_result; -- Результат: 2
Естественно их больше, если нужно что-то специфическое, обратитесь к документации.
Математические функции позволяют выполнять различные математические операции с данными.
Примеры:
ABS(x)— возвращает абсолютное значение числаx.ROUND(x, d)— округляет числоxдоdзнаков после запятой.CEIL(x)— округляет числоxдо ближайшего большего целого.FLOOR(x)— округляет числоxдо ближайшего меньшего целого.POWER(x, y)— возвращает результат возведенияxв степеньy.
Пример запроса:
SELECT ABS(-15) AS abs_value,
ROUND(123.4567, 2) AS rounded_value,
CEIL(4.3) AS ceil_value,
FLOOR(4.7) AS floor_value,
POWER(2, 3) AS power_value;Функции для работы со строками помогают манипулировать строковыми данными.
Примеры:
LENGTH(str)— возвращает длину строкиstr.UPPER(str)— преобразует строкуstrв верхний регистр.LOWER(str)— преобразует строкуstrв нижний регистр.SUBSTRING(str, start, length)— возвращает подстроку из строкиstr, начиная с позицииstartи длинойlength.TRIM(str)— удаляет пробелы с начала и конца строкиstr.
Пример запроса:
SELECT LENGTH('Hello, World!') AS length_value,
UPPER('hello') AS upper_value,
LOWER('WORLD') AS lower_value,
SUBSTRING('Hello, World!', 8, 5) AS substring_value,
TRIM(' Hello ') AS trimmed_value;Эти функции позволяют выполнять операции с датами и временем.
Примеры:
CURRENT_DATE— возвращает текущую дату.CURRENT_TIME— возвращает текущее время.DATEADD(interval, number, date)— добавляет заданное количество времени к дате.DATEDIFF(interval, date1, date2)— возвращает разницу между двумя датами.FORMAT(date, format)— форматирует дату в соответствии с заданным форматом.EXTRACT(what FROM what)- извлечь часть даты.
Пример запроса:
SELECT CURRENT_DATE AS current_date,
CURRENT_TIME AS current_time,
DATEADD(day, 5, '2023-08-01') AS new_date,
DATEDIFF(day, '2023-08-01', '2023-08-10') AS date_difference,
FORMAT(CURRENT_DATE, 'yyyy-MM-dd') AS formatted_date,
EXTRACT(YEAR FROM '2023-08-01');Оператор LIKE используется для поиска по шаблону в строках.
Примеры:
%— заменяет ноль или более символов._— заменяет ровно один символ.
Пример запроса:
SELECT *
FROM employees
WHERE name LIKE 'J%'; -- имена, начинающиеся с 'J'
SELECT *
FROM employees
WHERE name LIKE '_a%'; -- имена, где второй символ 'a'Функции форматирования позволяют изменить представление данных, например, чисел или дат.
Примеры:
FORMAT(number, format)— форматирует число в соответствии с заданным форматом.CAST(expression AS datatype)— преобразует одно значение в другой тип данных.
Пример запроса:
SELECT FORMAT(123456.789, '##,###.00') AS formatted_number,
CAST('2024-08-01' AS DATETIME) AS casted_date;Агрегатные функции выполняют вычисления над набором значений и возвращают одно значение.
Примеры:
COUNT(column)— возвращает количество строк.SUM(column)— возвращает сумму значений в колонке.AVG(column)— возвращает среднее значение.MAX(column)— возвращает максимальное значение.MIN(column)— возвращает минимальное значение.
Пример запроса:
SELECT COUNT(*) AS total_count,
SUM(salary) AS total_salary,
AVG(salary) AS average_salary,
MAX(salary) AS max_salary,
MIN(salary) AS min_salary
FROM employees;Обсудим GROUP BY и HAVING в SQL. Эти операторы позволяют группировать данные и фильтровать их на основе агрегатных
функций. Мы рассмотрим, как использовать эти операторы, приведем примеры запросов и разберем возможные применения.
Оператор GROUP BY используется для группировки строк, имеющих одинаковые значения в определенных столбцах. После
группировки можно применять агрегатные функции, такие как COUNT, SUM, AVG, MAX, MIN, к каждой группе.
Пример структуры запроса:
SELECT column1, column2, AGGREGATE_FUNCTION(column3)
FROM table_name
GROUP BY column1, column2;Пример запроса:
SELECT department, COUNT(employee_id) AS employee_count
FROM employees
GROUP BY department;В этом примере все сотрудники группируются по отделам, и для каждого отдела подсчитывается количество сотрудников.
Агрегатные функции играют важную роль при использовании GROUP BY. Вот несколько примеров:
COUNT(column)— подсчитывает количество строк в каждой группе.SUM(column)— суммирует значения столбца в каждой группе.AVG(column)— вычисляет среднее значение столбца в каждой группе.MAX(column)— находит максимальное значение в каждой группе.MIN(column)— находит минимальное значение в каждой группе.
Пример запроса:
SELECT department, AVG(salary) AS average_salary
FROM employees
GROUP BY department;Этот запрос группирует сотрудников по отделам и вычисляет среднюю зарплату в каждом отделе.
Оператор HAVING используется для фильтрации групп, образованных с помощью GROUP BY, на основе условий, которые
применяются к агрегатным функциям. Он аналогичен оператору WHERE, но применяется после группировки.
Пример структуры запроса:
SELECT column1, AGGREGATE_FUNCTION(column2)
FROM table_name
GROUP BY column1
HAVING AGGREGATE_FUNCTION(column2) condition;Пример запроса:
SELECT department, COUNT(employee_id) AS employee_count
FROM employees
GROUP BY department
HAVING COUNT(employee_id) > 10;Этот запрос группирует сотрудников по отделам и отображает только те отделы, в которых количество сотрудников больше 10.
Часто GROUP BY и HAVING используются вместе для выполнения сложных запросов.
Пример запроса:
SELECT department, AVG(salary) AS average_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;Этот запрос группирует сотрудников по отделам, вычисляет среднюю зарплату в каждом отделе и отображает только те отделы, где средняя зарплата превышает 50000.
Пример 1: Количество продаж по каждому продавцу
SELECT salesperson_id, COUNT(sale_id) AS total_sales
FROM sales
GROUP BY salesperson_id;Этот запрос отображает количество продаж, совершенных каждым продавцом.
Пример 2: Средняя оценка студентов по каждому курсу
SELECT course_id, AVG(grade) AS average_grade
FROM grades
GROUP BY course_id;Этот запрос группирует оценки студентов по курсам и вычисляет среднюю оценку для каждого курса.
Пример 3: Курсы с количеством студентов больше 30
SELECT course_id, COUNT(student_id) AS student_count
FROM enrollments
GROUP BY course_id
HAVING COUNT(student_id) > 30;Этот запрос отображает только те курсы, на которых зарегистрировано больше 30 студентов.
На самом деле в любом месте запроса, можно разместить другой запрос (внутри WHERE, внутри FROM итд)
SELECT *
FROM tbl
WHERE c1 > 5;
SELECT *
FROM tbl
WHERE c1 IN (1, 2, 3);
SELECT *
FROM tbl
WHERE c1 IN (SELECT c1 FROM t2);
SELECT *
FROM tbl
WHERE c1 IN (SELECT c3 FROM t2 WHERE c2 = tbl.c1 + 10);
SELECT *
FROM tbl
WHERE c1 BETWEEN (SELECT c3 FROM t2 WHERE c2 = tbl.c1 + 10) AND 100;
SELECT *
FROM tbl
WHERE EXISTS (SELECT c1 FROM t2 WHERE c2 > fdt.c1);Для упрощения понимания некоторых запросов, мы можем применить оператор WITH. Который по сути будет являться
переменной. В которую мы поместим какой-то запрос.
-- select top revenue months
WITH monthly_revenue AS (SELECT EXTRACT(YEAR FROM date) AS year,
EXTRACT(MONTH FROM date) AS month,
SUM(amount) AS total_amount
FROM revenue
GROUP BY year, month
ORDER BY year, month)
SELECT *
FROM monthly_revenue
WHERE total_amount > (SELECT SUM(total_amount) / 100 FROM monthly_revenue)
ORDER BY total_amount DESC;Получение самых прибыльных месяцев
Обсудим три мощных оператора в SQL: UNION, INTERSECT и EXCEPT. Эти операторы используются для комбинирования
результатов двух или более запросов, позволяя выполнять сложные операции с множествами данных. Давайте рассмотрим каждый
из них подробнее, включая синтаксис, примеры и случаи применения.
Оператор UNION объединяет результаты двух или более запросов в одну результирующую таблицу. Он исключает дублирующиеся
строки, возвращая только уникальные записи. Если необходимо сохранить дублирующиеся строки, используется
оператор UNION ALL.
Синтаксис:
SELECT column1, column2
FROM table1
UNION
SELECT column1, column2
FROM table2;Пример:
SELECT name, email
FROM customers
UNION
SELECT name, email
FROM prospects;Этот запрос объединяет списки имен и email-адресов из таблиц customers и prospects, исключая дубликаты.
Пример с UNION ALL:
SELECT name, email
FROM customers
UNION ALL
SELECT name, email
FROM prospects;Этот запрос объединяет списки имен и email-адресов, включая все дублирующиеся записи.
Оператор INTERSECT возвращает только те строки, которые присутствуют в обоих запросах. Он используется для нахождения
пересечения множеств данных.
Синтаксис:
SELECT column1, column2
FROM table1
INTERSECT
SELECT column1, column2
FROM table2;Пример:
SELECT name, email
FROM customers
INTERSECT
SELECT name, email
FROM newsletter_subscribers;Этот запрос возвращает список имен и email-адресов, которые есть как в таблице customers, так и в
таблице newsletter_subscribers.
Оператор EXCEPT возвращает строки из первого запроса, которых нет во втором запросе. Он используется для нахождения
разности множеств данных.
Синтаксис:
SELECT column1, column2
FROM table1
EXCEPT
SELECT column1, column2
FROM table2;Пример:
SELECT name, email
FROM customers
EXCEPT
SELECT name, email
FROM unsubscribed_users;Этот запрос возвращает список имен и email-адресов, которые есть в таблице customers, но отсутствуют в
таблице unsubscribed_users.
- Количество и типы столбцов: Все запросы, объединяемые с помощью
UNION,INTERSECTиEXCEPT, должны возвращать одинаковое количество столбцов, и типы данных этих столбцов должны быть совместимы. - Порядок сортировки: Для упорядочивания результатов объединенных запросов используется оператор
ORDER BYпосле всех объединенных запросов.
Пример с ORDER BY:
SELECT name, email
FROM customers
UNION
SELECT name, email
FROM prospects
ORDER BY name;Этот запрос объединяет списки имен и email-адресов, исключает дубликаты и сортирует результат по имени.
- Объединение данных из нескольких таблиц:
SELECT product_id, product_name
FROM warehouse_1
UNION
SELECT product_id, product_name
FROM warehouse_2;Этот запрос объединяет списки продуктов из двух складов.
- Поиск общих записей:
SELECT student_id, course_id
FROM course_enrollments_spring
INTERSECT
SELECT student_id, course_id
FROM course_enrollments_fall;Этот запрос находит студентов, которые зарегистрировались на один и тот же курс как весной, так и осенью.
- Исключение данных:
SELECT employee_id, name
FROM employees
EXCEPT
SELECT employee_id, name
FROM retired_employees;Этот запрос возвращает список действующих сотрудников, исключая тех, кто вышел на пенсию.
Использование оператора JOIN в SQL для объединения таблиц. Вы же еще помните, что таблицы в базе могут и даже должны
быть связаны? Так вот чаще всего нам нужно будет извлекать данных именно из связанных таблиц, а для этого нам
понадобится оператор JOIN
В SQL часто возникает необходимость упростить запись запросов, особенно когда таблицы имеют длинные названия. Для этого
можно использовать временные имена (алиасы). Алиасы создаются с помощью ключевого слова AS. Я уже использовал их чуть
выше в примерах, давайте разберемся
Пример:
SELECT e.name, d.name
FROM employees AS e
JOIN departments AS d ON e.department_id = d.id;В этом примере employees временно именуется как e, а departments — как d. Это делает запрос более читабельным и
менее громоздким.
Операторы JOIN используются для объединения строк из двух или более таблиц на основе связующего условия. Существует
несколько типов JOIN:
- INNER JOIN
- LEFT JOIN (или LEFT OUTER JOIN)
- RIGHT JOIN (или RIGHT OUTER JOIN)
- FULL JOIN (или FULL OUTER JOIN)
- CROSS JOIN
- SELF JOIN
Рассмотрим данные для примеров:
Таблица employees:
| employee_id | name | department_id | manager_id |
|---|---|---|---|
| 1 | Alice | 1 | NULL |
| 2 | Bob | 2 | 1 |
| 3 | Carol | 1 | 1 |
| 4 | Dave | NULL | 2 |
| 5 | Eve | 3 | 2 |
Таблица departments:
| department_id | name |
|---|---|
| 1 | Sales |
| 2 | Engineering |
| 3 | HR |
| 4 | Marketing |
INNER JOIN возвращает строки, у которых есть совпадающие значения в обеих таблицах.
Пример:
SELECT e.name AS employee_name, d.name AS department_name
FROM employees AS e
INNER JOIN departments AS d ON e.department_id = d.department_id;Результат:
| employee_name | department_name |
|---|---|
| Alice | Sales |
| Bob | Engineering |
| Carol | Sales |
| Eve | HR |
LEFT JOIN возвращает все строки из левой таблицы и совпадающие строки из правой таблицы. Если совпадений нет, то
возвращаются NULL для столбцов правой таблицы.
Пример:
SELECT e.name AS employee_name, d.name AS department_name
FROM employees AS e
LEFT JOIN departments AS d ON e.department_id = d.department_id;Результат:
| employee_name | department_name |
|---|---|
| Alice | Sales |
| Bob | Engineering |
| Carol | Sales |
| Dave | NULL |
| Eve | HR |
RIGHT JOIN возвращает все строки из правой таблицы и совпадающие строки из левой таблицы. Если совпадений нет, то
возвращаются NULL для столбцов левой таблицы.
Пример:
SELECT e.name AS employee_name, d.name AS department_name
FROM employees AS e
RIGHT JOIN departments AS d ON e.department_id = d.department_id;Результат:
| employee_name | department_name |
|---|---|
| Alice | Sales |
| Bob | Engineering |
| Carol | Sales |
| Eve | HR |
| NULL | Marketing |
FULL JOIN возвращает все строки, когда есть совпадения в левой или правой таблицах. Если совпадений нет, то
возвращаются NULL для отсутствующих совпадений с обеих сторон.
Пример:
SELECT e.name AS employee_name, d.name AS department_name
FROM employees AS e
FULL JOIN departments AS d ON e.department_id = d.department_id;Результат:
| employee_name | department_name |
|---|---|
| Alice | Sales |
| Bob | Engineering |
| Carol | Sales |
| Dave | NULL |
| Eve | HR |
| NULL | Marketing |
CROSS JOIN возвращает декартово произведение двух таблиц, то есть каждая строка из первой таблицы соединяется с каждой
строкой из второй таблицы.
Пример:
SELECT e.name AS employee_name, d.name AS department_name
FROM employees AS e
CROSS JOIN departments AS d;Результат:
| employee_name | department_name |
|---|---|
| Alice | Sales |
| Alice | Engineering |
| Alice | HR |
| Alice | Marketing |
| Bob | Sales |
| Bob | Engineering |
| Bob | HR |
| Bob | Marketing |
| Carol | Sales |
| Carol | Engineering |
| Carol | HR |
| Carol | Marketing |
| Dave | Sales |
| Dave | Engineering |
| Dave | HR |
| Dave | Marketing |
| Eve | Sales |
| Eve | Engineering |
| Eve | HR |
| Eve | Marketing |
SELF JOIN — это соединение таблицы с самой собой. Используется, когда нужно сравнить строки внутри одной таблицы.
Пример:
SELECT e1.name AS employee, e2.name AS manager
FROM employees AS e1
JOIN employees AS e2 ON e1.manager_id = e2.employee_id;Результат:
| employee | manager |
|---|---|
| Bob | Alice |
| Carol | Alice |
| Dave | Bob |
| Eve | Bob |
Рекурсивные запросы в SQL используются для работы с иерархическими данными, такими как структуры директорий или
организационные структуры. В SQL для этого используется конструкция WITH RECURSIVE.
Пример:
WITH RECURSIVE EmployeeHierarchy AS (SELECT employee_id, name, manager_id, 1 AS level
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.employee_id, e.name, e.manager_id, eh.level + 1
FROM employees AS e
JOIN EmployeeHierarchy AS eh ON e.manager_id = eh.employee_id)
SELECT employee_id, name, manager_id, level
FROM EmployeeHierarchy;Результат:
| employee_id | name | manager_id | level |
|---|---|---|---|
| 1 | Alice | NULL | 1 |
| 2 | Bob | 1 | 2 |
| 3 | Carol | 1 | 2 |
| 4 | Dave | 2 | 3 |
| 5 | Eve | 2 | 3 |
Этот запрос строит иерархию сотрудников, начиная с тех, у кого нет менеджера, и далее рекурсивно добавляя подчиненных.

