Какой полный базовый синтаксис оператора SELECT в SQL?

Ответ

Полная структура оператора SELECT (в порядке выполнения):

SELECT [DISTINCT | ALL] 
    { * | expression [[AS] alias], ... }
FROM 
    table_name [[AS] alias]
    [ { INNER | LEFT [OUTER] | RIGHT [OUTER] | FULL [OUTER] } JOIN 
        another_table ON join_condition ]
[WHERE 
    condition]
[GROUP BY 
    column1, column2, ...]
[HAVING 
    condition_after_grouping]
[ORDER BY 
    column1 [ASC | DESC], ...]
[OFFSET 
    n {ROW | ROWS}]
[FETCH {FIRST | NEXT} m {ROW | ROWS} ONLY];
-- или [LIMIT m [OFFSET n]] для MySQL/PostgreSQL

Логический порядок выполнения (не порядок написания):

  1. FROM / JOIN — определяет исходные таблицы.
  2. WHERE — фильтрует строки на уровне записей.
  3. GROUP BY — агрегирует строки в группы.
  4. HAVING — фильтрует сгруппированные данные.
  5. SELECT — вычисляет выражения и выбирает столбцы.
  6. DISTINCT — удаляет дубликаты.
  7. ORDER BY — сортирует результат.
  8. OFFSET / FETCH (LIMIT) — ограничивает вывод.

Пример комплексного запроса:

SELECT 
    d.name AS department,
    COUNT(e.id) AS employee_count,
    AVG(e.salary) AS avg_salary
FROM 
    departments d
    LEFT JOIN employees e ON d.id = e.department_id
WHERE 
    e.hire_date > '2020-01-01'
GROUP BY 
    d.id, d.name
HAVING 
    COUNT(e.id) > 5
ORDER BY 
    avg_salary DESC
OFFSET 0 ROWS
FETCH FIRST 10 ROWS ONLY;

Ответ 18+ 🔞

А, ну ты глянь, какой у нас тут учебник по SQL развернули, прямо как в старые добрые времена про Герасима с Муму! Только тут не собачку топить, а данные из базы вытаскивать. Сейчас разберём эту пиздопроебибну структуру, чтобы ты не метался потом, как тот самый немой, когда совесть загложет.

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

  1. FROM / JOIN — это, сука, самый первый шаг. Ты заходишь на склад (FROM) и начинаешь таскать оттуда все продукты — целые таблицы, блядь. А если надо несколько, то ты их склеиваешь, как блядь, пазл (JOIN). Без этого нихуя не начнётся, всё остальное — это уже обработка сырья.
  2. WHERE — а вот теперь ты смотришь на эту кучу сырых данных и начинаешь отбрасывать всякую хуйню. «А этот сотрудник уволился в 2019? Нахуй в ведро. А этот получает три копейки? Тоже в пизду». Фильтруешь строки, пока они ещё не сгруппированы.
  3. GROUP BY — тут начинается магия. Ты берёшь отфильтрованную кучу и начинаешь её прессовать. Всех сотрудников по отделам в кучки, все продажи по датам. Из многих строк делаешь мало групп. Овердохуища строк схлопнулось в несколько строчек с суммами да средними.
  4. HAVING — а это фильтр уже для этих самых сгруппированных, спрессованных результатов. «О, этот отдел после группировки имеет 2 человека? Нахуй, нам нужны только где больше 5». WHERE работает ДО группировки, а HAVING — ПОСЛЕ. Запомни, а то будешь как Герасим — «Муму...» — и нихуя не выйдет.
  5. SELECT — и только сейчас, блядь, когда всё отфильтровано и сгруппировано, ты решаешь, ЧТО ИМЕННО показать на тарелке. Рассчитываешь среднюю зарплату (AVG), переименовываешь столбцы (AS), выбираешь только нужные поля. До этого шага тебе похуй, какие столбцы в SELECT написаны.
  6. DISTINCT — убрать дубликаты из того, что уже выбрал. Типа «ой, бля, два раза один и тот же департамент вылез, убери один нахуй».
  7. ORDER BY — ну и теперь, когда блюдо готово, его можно красиво разложить по тарелке. Отсортировать от большего к меньшему, по алфавиту — дело хозяйское.
  8. OFFSET / FETCH (LIMIT) — а это, сука, порционирование. «Гостей много, всем не хватит. Дайте мне первые 10 (FETCH FIRST 10 ROWS) самых жирных записей, а первые пять (OFFSET 5) — пропустите, они на пробу шефу».

А вот тебе живой пример, чтобы в голове осел, как этот цирк работает:

SELECT
    d.name AS department, -- 5. Выбрать к переименовать
    COUNT(e.id) AS employee_count, -- 5. Посчитать
    AVG(e.salary) AS avg_salary -- 5. Посчитать среднее
FROM
    departments d -- 1. Пойти на склад "departments"
    LEFT JOIN employees e ON d.id = e.department_id -- 1. Приклеить к нему "employees"
WHERE
    e.hire_date > '2020-01-01' -- 2. Отфильтровать: только новички после 2020
GROUP BY
    d.id, d.name -- 3. Схлопнуть всё по отделам
HAVING
    COUNT(e.id) > 5 -- 4. Оставить только отделы, где больше 5 человек (уже после схлопывания!)
ORDER BY
    avg_salary DESC -- 7. Отсортировать по ЗП, чтоб самые щедрые сверху
OFFSET 0 ROWS -- 8. Ничего не пропускать
FETCH FIRST 10 ROWS ONLY; -- 8. Показать только топ-10

Вот и весь сказ, ёпта. Главное — не путай порядок выполнения с порядком написания, а то получится как в той истории: «Ядрёна вошь! Хотел сначала отсортировать, а данных-то ещё нет!». В рот меня чих-пых, теперь-то понятно?