Техническое собеседование: 10 каверзных вопросов по SQL

Здравствуйте, коллеги. Представляю вам небольшую подборку каверзных вопросов по нашему любимому языку структурированных запросов. Список составлен на основе моего собственного опыта работы и хождения по собеседованиям. Я старался отбирать только те вопросы, ответы на которые могут помочь на практике, а не только на техническом собеседовании. Вопросы касаются базовых механизмов языка, потому в первую очередь будут интересны новичкам, но, возможно, и матерые разработчики узнают из них что-то новое. Итак, приступим.

1. Что вернет условие 2 <> NULL?

Сравнение с NULL — это, наверное, первый подводный камень, на который натыкаются люди при работе с базой данных. Вопреки привычной логике условие

2 <> NULL

возвращает ложь (FALSE), как впрочем и условие

2 = NULL

Дело здесь в том, что тип значения NULL в SQL имеет несколько другой оттенок значения, чем в прикладных языках программирования. Если в С-подобных языках NULL значит отсутствие какого-то значения, то в SQL он значит лишь то, что мы не знаем этого значения. По этой причине любое сравнение с NULL возвращает ложь.

Возвращаясь к сути вопроса, мы не можем сказать «Два не равно NULL» потому, что мы не знаем значения справа от знака неравенства, а там как раз может оказаться двойка.

2. Что вернет условие 3 NOT IN (1, 2, NULL)?

Здесь та же история, что и в предыдущем случае. Условие

3 NOT IN (1, 2, NULL)

возвращает ложь (FALSE), как и условие

3 IN (1, 2, NULL)

Причина этого заключается в особенностях работы оператора IN. Проверяя, что определенное значение входит в коллекцию, оператор IN просто сравнивает это значение с каждым элементом коллекции.

Другими словами:

3 IN (1, 2, NULL)

это то же самое, что и

(3 = 1) OR (3 = 2) OR (3 = NULL)

В случае с NOT IN условие:

3 NOT IN (1, 2, NULL)

это то же самое, что и

(3 <> 1) AND (3 <> 2) AND (3 <> NULL)

Как мы знаем из предыдущего примера, 3 <> NULL возвращает ложь, а значит и все условие
(3 <> 1) AND (3 <> 2) AND (3 <> NULL)

тоже будет ложным.

3. Выполнится ли этот запрос?

SELECT 
	order_id,
	order_code,
	SUM(order_value)
FROM 
	orders
GROUP BY
	order_id

Едино правильного ответа на этот вопрос нет — все зависит от базы данных. Проблема этого запроса заключается в том, что колонка order_code не указана в выражении GROUP BY и при этом для нее не определена агрегатная функция. То есть по отношению к колонке order_code мы не знаем группировать ее или группировать по ней.

Если этот запрос будет выполняться в MySQL, то колонка order_code добавится в выражение GROUP BY автоматически и запрос выполнится нормально. Если же этот запрос будет выполняться MS SQL Server, то по умолчанию будет сгенерирована ошибка. Впрочем, это поведение настраивается.

4. Почему не выполнится этот запрос?

SELECT 
	user_name,
	YEAR(user_birth_date) AS year_of_birth
FROM 
	users
WHERE
	year_of_birth = 2000

Запрос не выполнится из-за обращения к псевдониму year_of_birth в выражении WHERE. Дело в том, что псевдонимы полей в SQL используются для форматирования данных уже полученных из базы. Поэтому их можно использовать только в выражениях, которые отвечают за оформление результата, таких как GROUP BY, ORDER BY и HAVING. В выражениях, отвечающих за получение данных, таких как WHERE, нужно использовать оригинальные имена полей.

WHERE
	YEAR(user_birth_date) = 2000

5. Имеет ли значение порядок колонок в составном индексе?

Да.

CREATE NONCLUSTERED INDEX MyInd on users (user_name, user_birth_date);

это не то же самое, что

CREATE NONCLUSTERED INDEX MyInd on users (user_birth_date, user_name);

При создании составного индекса сначала строится обычный индекс для его первой колонки, а потом уже на основе него строится индекс для второй колонки и так дальше.

Другими словами, колонки, по которым поиск выполняется чаще всего, должны стоять в составном индексе первыми.

6. Какая разница между TRUNCATE TABLE table_name и DELETE FROM table_name?

Фактически обе эти команды вызовут удаление всех строк из таблицы под названием table_name, но вот произойдет это совсем по-разному:

  1. При вызове команды TRUNCATE таблица полностью сбрасывается и создается снова, в то время как команда DELETE удаляет каждую строку таблицы по отдельности. Из-за этого TRUNCATE отрабатывает значительно быстрее.
  2. Как следствие первого пункта, команда TRUNCATE не вызывает срабатывание триггеров и правил внешних ключей, то есть, очищая таблицу таким способом, можно не бояться каскадного удаления или изменения данных в других таблицах.
  3. В отличие от DELETE команда TRUNCATE не транзакционная. То есть, если в момент ее вызова, таблица table_name будет заблокирована какой-либо транзакцией — может возникнуть ошибка.

7. Какая разница между типами CHAR и VARCHAR?

Оба эти типа используются для хранения текстовой информации ограниченной длины, а различия между ними следующие:

  1. Тип CHAR хранит значение фиксированной длины. Если строка, помещаемая в колонку данного типа, имеет меньшую длину, чем длина типа — строка будет дополнена пробелами. Например, если в колонку типа CHAR(10) записать строку SQL, то она сохранится как SQL       .

    Тип VARCHAR хранит значение переменной длины. Под каждое значение этого типа выделяется столько памяти, сколько нужно для этого конкретного значения.

  2. Для типа CHAR используется статическое распределение памяти, из-за чего операции с ним быстрее, чем с VARCHAR.

Таким образом, тип CHAR подходит для хранения строковых данных фиксированной длины (например, инвентарных номеров, хешей), а для остальных строк больше подойдут VARCHAR или NVARCHAR.

8. Какая разница между типами VARCHAR и NVARCHAR?

Тип NVARCHAR, пожалуй, самый универсальный из строчных типов данных в БД. Он позволяет хранить строки переменной длины в формате Unicode. В этом формате каждый символ занимает 2 байта, а сама кодировка содержит 65 536 символов и включает в себя все языки мира, в том числе иероглифы.

Тип VARCHAR хранит данные в формате SACII. В этом формате каждый символ занимает 1 байт, но отельная кодировка содержит всего 256 символов. Из-за этого для каждого мирового языка выделяется своя кодировка.

Таким образом, в формате VARCHAR стоит хранить строчные данные, которые точно не придется переводить (например, адреса электронной почты). Для других случаев больше подойдет NVARCHAR.

9. Какая разница между UNION и UNION ALL?

Выражения UNION и UNION ALL — это очень надежные поставщики лишних или недостающих строк в результате запроса. Оба эти выражения используются, чтобы объединить результаты нескольких независимых друг от друга запросов. А разница между ними заключается в том, что, если в результатах запросов есть одинаковые строки, то UNION удалит дубликаты, оставив только одну из таких строк. В то же время UNION ALL, как можно догадаться из названия, просто объединит результаты запросов, не обращая внимания на дубликаты.

10. Какая разница между выражениями WHERE и HAVING?

Ну и наконец, вопрос, который задают практически на каждом собеседовании по базам данных: про HAVING.
Выражения WHERE и HAVING используются для фильтрации результата запроса и ожидают после себя некоторое условие, по которому нужно отфильтровать данные. Но, если WHERE работает само по себе и фильтрует данные каждой строки результата по отдельности, то выражение HAVING имеет смысл только в сочетании с выражением GROUP BY и фильтрует уже сгруппированные значения.


Спасибо за внимание. Пишите в комментариях, на сколько вопросов вы знали ответ, а также с какими хитрыми задачами по SQL вам самим приходилось сталкиваться.

Похожие статьи:
В январе вышла моя статья про типы машинного обучения и способы их применения для повседневных задач. Спасибо всем за фидбэк...
В свое время я зачитывался Рихтером и усиленно штудировал Шилдта. Думал, что буду заниматься разработкой под .NET, но судьба...
Президент Зеленський виступив на спецзасіданні Радбезу ООН щодо різанини в Бучі, низка європейських країн вислали...
Необходимо сделать лирическое отступление и констатировать факт, что со времени написания оригинальной серии...
Британська Fintech Farm, мажоритарним власником якої є Дмитро Дубілет, закрила раунд інвестицій на понад $20 млн, про...
Яндекс.Метрика