🔥 Важное для QA-специалистов! 🔥
В QaRocks ты найдешь туториалы, задачи и полезные книги, которых нет в открытом доступе. Уже более 14.000 подписчиков – будь среди нас! Заходи к нам в телеграм канал QaRocks
Мы собрали основные вопросы по SQL, ответы на которые должны знать лучшие тестировщики. Представляем вашему вниманию первую часть.
1. Что делает UNION? В чем разница между UNION и UNION ALL?
UNION
объединяет содержимое двух структурно совместимых таблиц в одну общую таблицу. Разница между UNION
и UNION ALL
заключается в том, что UNION
исключает повторяющиеся записи, тогда как UNION ALL
включает дубликаты записей.
Важно отметить, что производительность UNION ALL
обычно выше, чем у UNION
, поскольку UNION
требует от сервера дополнительной работы по удалению дубликатов.
Поэтому в случаях, когда точно известно, что дубликатов не будет, или когда их наличие не является проблемой, рекомендуется использовать UNION ALL
из соображений производительности.
2. Перечислите и объясните различные типы операторов JOIN
, поддерживаемые в стандарте ANSI SQL.
ANSI-стандарт SQL определяет пять типов операторов JOIN
:
INNER JOIN
: Возвращает все строки, для которых есть хотя бы одно совпадение в ОБЕИХ таблицах. Это тип соединения по умолчанию, если не указан конкретный типJOIN
.LEFT JOIN
(илиLEFT OUTER JOIN
): Возвращает все строки из левой таблицы и соответствующие строки из правой таблицы; т.е. результаты будут содержать все записи из левой таблицы, даже если условиеJOIN
не найдёт соответствующих записей в правой таблице.RIGHT JOIN
(илиRIGHT OUTER JOIN
): Возвращает все строки из правой таблицы и соответствующие строки из левой таблицы. Это полная противоположностьLEFT JOIN
; т.е. результаты будут содержать все записи из правой таблицы, даже если условиеJOIN
не найдет соответствующих записей в левой таблице.FULL JOIN
(илиFULL OUTER JOIN
): Возвращает все строки, для которых есть совпадения в ЛЮБОЙ из таблиц. КонцептуальноFULL JOIN
сочетает в себе эффект применения какLEFT JOIN
, так иRIGHT JOIN
; т.е. его набор результатов эквивалентен выполнениюUNION
результатов левого и правого внешних запросов.CROSS JOIN
: Возвращает все записи, в которых каждая строка из первой таблицы объединяется с каждой строкой из второй таблицы (т.е. возвращает декартово произведение наборов строк из соединяемых таблиц).
3. В таблице приведены следующие данные:
sql> SELECT * FROM runners; +----+--------------+ | id | name | +----+--------------+ | 1 | John Doe | | 2 | Jane Doe | | 3 | Alice Jones | | 4 | Bobby Louis | | 5 | Lisa Romero | +----+--------------+ sql> SELECT * FROM races; +----+----------------+-----------+ | id | event | winner_id | +----+----------------+-----------+ | 1 | 100 meter dash | 2 | | 2 | 500 meter dash | 3 | | 3 | cross-country | 2 | | 4 | triathalon | NULL | +----+----------------+-----------+
Каким будет результат запроса, приведенного ниже?
SELECT * FROM runners WHERE id NOT IN (SELECT winner_id FROM races)
Объясните свой ответ, а также предложите альтернативную версию этого запроса, которая позволит избежать выявленной проблемы.
Учитывая предоставленную выборку данных, результат этого запроса будет пустым. Причина этого заключается в следующем: если условие SQL NOT IN
содержит какие-либо значения null, то внешний запрос в данном случае вернет пустой результат, даже если существует много id в таблице runners
, которые соответствуют winner_ids в таблице races
.
Зная это, запрос, позволяющий избежать этой проблемы, будет выглядеть следующим образом:
SELECT * FROM runners WHERE id NOT IN (SELECT winner_id FROM races WHERE winner_id IS NOT null)
Обратите внимание, что здесь предполагается стандартное поведение SQL, которое вы получите без изменения стандартной настройки ANSI_NULLS
по умолчанию.
🔥 Хочешь больше SQL Задачек??? 🔥
В канале SqlQuestions более 1000 разных SQL задач с ответами. Переходи и посмотри
4. Даны две таблицы, созданные и заполненные следующим образом:
CREATE TABLE dbo.envelope(id int, user_id int); CREATE TABLE dbo.docs(idnum int, pageseq int, doctext varchar(100)); INSERT INTO dbo.envelope VALUES (1,1), (2,2), (3,3); INSERT INTO dbo.docs(idnum,pageseq) VALUES (1,5), (2,6), (null,0);
Какой результат будет получен при выполнении следующего запроса:
UPDATE docs SET doctext=pageseq FROM docs INNER JOIN envelope ON envelope.id=docs.idnum WHERE EXISTS ( SELECT 1 FROM dbo.docs WHERE id=envelope.id );
Объясните свой ответ.
Результат выполнения запроса будет следующим:
idnum pageseq doctext 1 5 5 2 6 6 NULL 0 NULL
Условие EXISTS
в приведенном выше запросе всегда будет истинным, поскольку ID
не является полем таблицы dbo.docs
. Таким образом, оно будет ссылаться на таблицу envelope
, сравнивая её саму с собой!
Значение idnum
, равное NULL
, не будет установлено, поскольку соединение со значением NULL
не даст результата при попытке сопоставления с любым значением из таблицы envelope
.
5. Дана схема таблиц: Emp(Id, Name, DeptId), Dept(Id, Name)
Если таблица Emp
содержит 10 записей, а таблица Dept
– 5 записей, сколько строк будет возвращено в результате выполнения следующего SQL-запроса:
Select * From Emp, Dept
Объясните свой ответ.
Запрос вернет 50 строк, формируя «декартово произведение» или «перекрёстное соединение», которое является результатом по умолчанию при отсутствии условия WHERE
.
6. Даны две таблицы, созданные следующим образом:
create table test_a(id numeric); create table test_b(id numeric); insert into test_a(id) values (10), (20), (30), (40), (50); insert into test_b(id) values (10), (30), (50);
Напишите запрос для выборки значений из таблицы test_a
, которые отсутствуют в test_b
, не используя ключевое слово NOT.
Обратите внимание, что Oracle не поддерживает приведенный выше синтаксис INSERT
, поэтому потребуется использовать следующий вариант:
insert into test_a(id) values (10); insert into test_a(id) values (20); insert into test_a(id) values (30); insert into test_a(id) values (40); insert into test_a(id) values (50); insert into test_b(id) values (10); insert into test_b(id) values (30); insert into test_b(id) values (50);
В SQL Server, PostgreSQL и SQLite это можно сделать с помощью ключевого слова except
следующим образом:
select * from test_a except select * from test_b;
В Oracle вместо этого используется ключевое слово minus
. Обратите внимание, что при наличии нескольких столбцов (например ID и Name) в запросах Oracle следует явно указывать столбец: Select ID from test_a minus select ID from test_b
MySQL не поддерживает функцию except
. Однако существует стандартное SQL-решение, которое работает во всех вышеперечисленных СУБД, включая MySQL:
select a.id from test_a a left join test_b b on a.id = b.id where b.id is null;
7. Напишите SQL-запрос для нахождения 10-й наибольшей зарплаты сотрудника из таблицы Employee
. Объясните свой ответ.
(Примечание: Можно предположить, что в таблице Employee
есть как минимум 10 записей.)
Это можно сделать следующим образом:
SELECT TOP (1) Salary FROM ( SELECT DISTINCT TOP (10) Salary FROM Employee ORDER BY Salary DESC ) AS Emp ORDER BY Salary
Принцип работы:
Сначала запрос SELECT DISTINCT TOP (10) Salary FROM Employee ORDER BY Salary DESC
выберет 10 самых высоких зарплат в таблице. Однако эти зарплаты будут отсортированы по убыванию. Это было необходимо для работы первого запроса, но если теперь выбрать верхнюю строку из этого списка, вы получите самую высокую зарплату, а не 10-ю.
Поэтому второй запрос переупорядочивает эти 10 записей по возрастанию (используя порядок сортировки по умолчанию), а затем выбирает верхнюю запись (которая теперь будет наименьшей из этих 10 зарплат).
Не все базы данных поддерживают ключевое слово TOP
. Например, в MySQL и PostgreSQL используется ключевое слово LIMIT
, как показано ниже:
SELECT Salary FROM ( SELECT DISTINCT Salary FROM Employee ORDER BY Salary DESC LIMIT 10 ) AS Emp ORDER BY Salary LIMIT 1;
Или в более краткой форме для MySQL:
SELECT DISTINCT Salary FROM Employee ORDER BY Salary DESC LIMIT 9,1;
А в PostgreSQL это можно сделать так:
SELECT DISTINCT Salary FROM Employee ORDER BY Salary DESC LIMIT 1 OFFSET 9;
8. Напишите SQL-запрос с использованием UNION ALL
(не UNION
), который применяет WHERE
для исключения дубликатов.
Вы можете избежать дубликатов с помощью UNION ALL
и при этом работать гораздо быстрее, чем с UNION DISTINCT
(который фактически идентичен UNION), выполнив запрос следующим образом:
SELECT * FROM mytable WHERE a=X UNION ALL SELECT * FROM mytable WHERE b=Y AND a!=X
Ключевым моментом является часть AND a!=X
. Это дает вам преимущества команды UNION
, избегая при этом значительного снижения производительности.
9. Даны следующие таблицы:
SELECT * FROM users; user_id username 1 John Doe 2 Jane Don 3 Alice Jones 4 Lisa Romero SELECT * FROM training_details; user_training_id user_id training_id training_date 1 1 1 "2015-08-02" 2 2 1 "2015-08-03" 3 3 2 "2015-08-02" 4 4 2 "2015-08-04" 5 2 2 "2015-08-03" 6 1 1 "2015-08-02" 7 3 2 "2015-08-04" 8 4 3 "2015-08-03" 9 1 4 "2015-08-03" 10 3 1 "2015-08-02" 11 4 2 "2015-08-04" 12 3 2 "2015-08-02" 13 1 1 "2015-08-02" 14 4 3 "2015-08-03"
Напишите запрос для получения списка пользователей, которые посетили обучающий урок более одного раза в один и тот же день, сгруппированный по пользователю и обучающему уроку, отсортированных от самой последней даты обучения до самой старой даты.
SELECT u.user_id, username, training_id, training_date, count( user_training_id ) AS count FROM users u JOIN training_details t ON t.user_id = u.user_id GROUP BY u.user_id, username, training_id, training_date HAVING count( user_training_id ) > 1 ORDER BY training_date DESC;
user_id username training_id training_date count 4 Lisa Romero 2 August, 04 2015 00:00:00 2 4 Lisa Romero 3 August, 03 2015 00:00:00 2 1 John Doe 1 August, 02 2015 00:00:00 3 3 Alice Jones 2 August, 02 2015 00:00:00 2
10. Что такое план выполнения запроса? Когда его используют? Как его просмотреть?
План выполнения запроса – это, по сути, дорожная карта, на которой в графической или текстовой форме показаны методы получения данных, выбранные оптимизатором запросов SQL-сервера для хранимой процедуры или ad hoc запроса.
Планы выполнения очень полезны для тестировщика, т.к. помогают понять и проанализировать характеристики производительности запроса или хранимой процедуры.
Во многих SQL-системах просмотреть план выполнения запроса можно с помощью ключевого слова EXPLAIN
. В Microsoft SQL Server анализатор запросов имеет опцию “Show Execution Plan” (находится в выпадающем меню Query). Если эта опция включена, то при запуске запроса в отдельном окне будут отображаться планы выполнения запроса.
Перевод статьи «41 Essential SQL Interview Questions».