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

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

@ironcomp

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

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  ordersGROUP 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_birthFROM  usersWHERE 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и фильтрует уже сгруппированные значения

Report Page