Руководство по подготовке к собеседованию по SQL

Руководство по подготовке к собеседованию по SQL

https://t.me/Chatgpturbobot - chatgpt 4 версии.

Вопросы по SQL — одна из ключевых тем собеседования на должность аналитика данных или продукции, а также бизнес-аналитика. Крупные технологические компании, в том числе иностранные, такие как Amazon, Uber и Facebook, особенно тщательно проверяют знания претендента в этой области.

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

Задачи по SQL можно разделить на 4 уровня. В рамках гайда мы рассмотрим каждый из них вместе со стандартными примерами для практики. Если хотите лучше усвоить материал, не переходите сразу же к решению.

Уровень 1. Задачи, основанные на агрегатных функциях

Язык SQL отлично подходит для агрегации. Для этого есть множество функций, например SUM()AVG()MAX()MIN()COUNT() и т. д. Знание таких функций — это базовый уровень знаний, который ожидается от кандидата.


Рассмотрим следующую таблицу сотрудников. В каждой строке указаны данные о сотруднике — отдел, зарплата, руководитель и т. д.

-- Table: employees
-- | dept_id | employee_id | amount | manager_id |
-- |---------|-------------|--------|------------|
-- | 1       | 1           | 8000   |     3      |
-- | 1       | 2           | 5000   |     3      |
-- | 1       | 3           | 10000  |   null     |
-- | 2       | 4           | 15000  |   null     |
-- | 2       | 5           | 16000  |     4      |
-- | 3       | 6           | 8000   |   null     |

На основе этой таблицы напишите SQL-запрос, чтобы найти идентификаторы сотрудников, которые зарабатывают больше других в каждом из отделов.

Лучший способ решить любую задачу — это представить ее в виде пошаговой логики. В данном случае мы определяем наибольшую сумму по каждому отделу. Затем определяем формат вывода, для чего нужен только показатель employee_id.

-- Часть 1: Получаем самую высокую зарплату в каждом отделе
 SELECT max(amount) AS salary 
 From employees 
 GROUP BY dept_id
 
 -- Часть 2: Получаем желаемый формат вывода employee_id
 -- Поскольку employee_id нельзя напрямую использовать в группе путем агрегации, мы можем прибегнуть к подзапросам.
 
 SELECT e1.employee_id
 FROM employees e1 
 WHERE e1.amount IN (
                      SELECT max(e2.amount) AS amount 
                      From employees as e2
                      GROUP BY e2.dept_id
                      HAVING e1.dept_id = e2.dept_id )

Уровень 2. Задачи, основанные на операциях JOIN и SET

SQL предоставляет возможность объединять результаты из двух или более таблиц с помощью операций JOIN и SET. К популярным JOIN-операциям относятся inner joinleft joinright join и cross join. Наиболее известные SET-операторы — UNIONUNION ALLEXCEPTINTERCEPT и др.


Вернемся к таблице сотрудников, представленной выше. Напишите SQL-запрос, чтобы определить сотрудников, которые зарабатывают больше, чем их руководитель.

-- Часть 1: Поставьте рядом зарплату менеджера и зарплату сотрудника с помощью self join

SELECT e1.employee_id
FROM employees as e1
LEFT JOIN employees as e2 ON e1.manager_id = e2.employee_id

-- Часть 2: Отфильтруйте сотрудников, которые зарабатывают больше, чем менеджер

SELECT e1.employee_id
FROM employees as e1
LEFT JOIN employees as e2 ON e1.manager_id = e2.employee_id
AND e1.amount > e2.amount

Уровень 3. Задачи на основе функции Windows

Функции Windows, также известные как аналитические функции, — это самая удивительная особенность языка SQL. Вот несколько популярных аналитических функций: RANK()DENSE_RANK()LEAD()LAG() и т. д.


Вернемся к первой задаче. Мы использовали подзапрос, чтобы определить сотрудника, получающего самую высокую зарплату. Сделать то же самое можно и с помощью функции Windows. Попробуйте решить эту задачу, не глядя на решение.

-- Часть 1: Проранжируйте идентификаторы сотрудников по наибольшей зарплате для каждого отдела с помощью функции DENSE_RANK()

SELECT employee_id, 
       DENSE_RANK() OVER (PARTITION BY dept_id ORDER BY amount desc) rnk
from employees

-- Часть 2: Отфильтруйте строки, в которых rnk = 1

SELECT employee_id
FROM
(SELECT employee_id, 
       DENSE_RANK() OVER (PARTITION BY dept_id ORDER BY amount desc) rnk
from employees) a
WHERE rnk = 1

Уровень 4. Задачи, основанные на комбинации вышеупомянутых уровней

С первого взгляда некоторые задачи могут показаться сложными. Лучшей стратегией их решения признан пошаговый логический подход. Разбейте задачу на мелкие составляющие.


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

Рассмотрим следующую таблицу посещаемости. Каждая строка содержит идентификатор сотрудника и дату посещения офиса.

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

-- Table: attendance
-- | employee_id | attend_dt   | 
-- |-------------|-------------|
-- | 1           | 2022-01-01  |
-- | 1           | 2022-01-02  |
-- | 1           | 2022-01-05  |
-- | 2           | 2022-01-01  |
-- | 2           | 2022-01-02  |
-- | 2           | 2022-01-04  |
--`| 2           | 2022-01-05  |
-- | 2           | 2022-01-06  |
-- | 3           | 2022-01-02  |
-- | 3           | 2022-01-04  |

-- Table: employees
-- | employee_id | name        | 
-- |-------------|-------------|
-- | 1           |  samuel     |
-- | 2           |  karthik    |
-- | 3           |  casey      |
-- Часть 1: Присвойте идентификатор каждой строке в таблице
select * , row_number() over (partition by employee_id order by attend_dt asc) rn
from attendance

-- часть 2: Найдите показатель day из поля даты и разницу между rn и day
-- Это поможет нам в создании групп непрерывных рядов

select *, day(attend_at) - rn
from
(select *, row_number() over (partition by employee_id order by attend_at asc) rn
from attendance)

-- Теперь наша таблица будет выглядеть следующим образом
-- rn| employee_id | attend_dt   |day|group_name(day-rn)|                                                
-- --|-------------|-------------|---|------------------
-- 1 | 1           | 2022-01-01  |1  |0
-- 2 | 1           | 2022-01-02  |2  |0
-- 3 | 1           | 2022-01-05  |5  |2
-- 1 | 2           | 2022-01-01  |1  |0
-- 2 | 2           | 2022-01-02  |2  |0
-- 3 | 2           | 2022-01-04  |4  |1
-- 4 | 2           | 2022-01-05  |5  |1
-- 5 | 2           | 2022-01-06  |6  |1
-- 1 | 3           | 2022-01-02  |2  |1
-- 2 | 3           | 2022-01-04  |4  |2

-- Часть 3 : Находим количество для каждого показателя group_name и каждого сотрудника

select employee_id, group_name, count(*) streak
from
(select *, (day(attend_at) - rn ) group_name
from
(select *, row_number() over (partition by employee_id order by attend_at asc) rn
from attendance) a ) b
group by employee_id, group_name

-- Часть 4 : Находим самый длинный ряд событий

select employee_id, max(streak) longest_streak
from
(select employee_id, group_name, count(*) streak
from
(select *, (day(attend_at) - rn ) group_name
from
(select *, row_number() over (partition by employee_id order by attend_at asc) rn
from attendance) a ) b
group by employee_id, group_name ) c

-- Часть 5 : Упорядочиваем данные в желаемом выходном формате

select e.name, d.longest_streak
from
(select employee_id, max(streak) longest_streak
from
(select employee_id, group_name, count(*) streak
from
(select *, (day(attend_at) - rn ) group_name
from
(select *, row_number() over (partition by employee_id order by attend_at asc) rn
from attendance) a ) b
group by employee_id, group_name ) c ) d 
join
(select *
from employees) e on d.employee_id = e.employee_id

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

источник


Report Page