SELECT в Oracle SQL. Введение
SELECT — основной оператор выборки в Oracle SQL. Он строит результирующие наборы из таблиц и представлений, поддерживает фильтрацию, сортировку, группировку, подзапросы, соединения, аналитические функции и многое другое.
Где используют
- Отчёты и витрины: агрегации, сортировки, ограничение объёма выдачи.
- Аналитика: оконные функции, ранжирование, скользящие расчёты.
- Иерархии и графы: запросы с
CONNECT BYи рекурсивныйWITH. - Интеграции: подзапросы, JSON/XML‑извлечение,
PIVOT/UNPIVOT.
Синтаксис SELECT
-- Базовый шаблон
SELECT [DISTINCT] expr_list
FROM source
[WHERE condition]
[GROUP BY expr_list]
[HAVING condition]
[ORDER BY sort_list]
[OFFSET n ROWS] [FETCH {FIRST|NEXT} m ROWS {ONLY|WITH TIES}];
-- Примеры подзапросов и соединений
SELECT a.col, b.col
FROM a
JOIN b ON b.a_id = a.id;
100 простых примеров SELECT
1. Все колонки из таблицы
SELECT *
FROM employees;2. Только нужные поля
SELECT emp_id, emp_name, hire_date
FROM employees;3. Псевдонимы для удобного вывода
SELECT emp_name AS name, salary AS sal
FROM employees;4. Арифметика и округление
SELECT emp_id, salary, ROUND(salary * 1.2, 2) AS salary_with_bonus
FROM employees;5. DISTINCT для уникальных значений
SELECT DISTINCT dept_id
FROM employees;6. Фильтрация по условию
SELECT emp_id, emp_name
FROM employees
WHERE dept_id = 10 AND salary > 5000;7. Диапазон через BETWEEN
SELECT emp_id, salary
FROM employees
WHERE salary BETWEEN 3000 AND 7000;8. Список значений через IN
SELECT emp_id, dept_id
FROM employees
WHERE dept_id IN (10,20,30);9. Поиск по шаблону (LIKE)
SELECT emp_id, emp_name
FROM employees
WHERE emp_name LIKE 'A%';10. Проверка на NULL
SELECT emp_id, manager_id
FROM employees
WHERE manager_id IS NULL;11. Сортировка по одному полю
SELECT emp_id, emp_name, salary
FROM employees
ORDER BY salary DESC;12. Сортировка по нескольким полям
SELECT emp_id, emp_name, dept_id, salary
FROM employees
ORDER BY dept_id, salary DESC;13. Ограничение выдачи (FETCH FIRST)
SELECT emp_id, salary
FROM employees
ORDER BY salary DESC
FETCH FIRST 10 ROWS ONLY;14. Пагинация через OFFSET/FETCH
SELECT emp_id, emp_name
FROM employees
ORDER BY emp_id
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;15. Агрегация по отделам
SELECT dept_id, AVG(salary) AS avg_sal, COUNT(*) AS cnt
FROM employees
GROUP BY dept_id;16. Фильтр агрегатов (HAVING)
SELECT dept_id, AVG(salary) AS avg_sal
FROM employees
GROUP BY dept_id
HAVING AVG(salary) > 6000;17. Производное поле через CASE
SELECT emp_name,
CASE WHEN salary >= 6000 THEN 'HIGH' ELSE 'NORMAL' END AS band
FROM employees;18. Подзапрос в IN
SELECT emp_id, emp_name
FROM employees
WHERE dept_id IN (SELECT dept_id FROM departments WHERE region = 'EU');19. EXISTS с корреляцией
SELECT d.dept_id, d.dept_name
FROM departments d
WHERE EXISTS (
SELECT 1 FROM employees e
WHERE e.dept_id = d.dept_id
AND e.salary > 8000
);20. Скалярный подзапрос в списке вывода
SELECT emp_id, (SELECT dept_name FROM departments d WHERE d.dept_id = e.dept_id) AS dept_name
FROM employees e;Еще 20 примеров.
21. Перекрёстное соединение
SELECT a.*, b.*
FROM a
CROSS JOIN b;22. Внутреннее соединение по ключу
SELECT e.emp_name, d.dept_name
FROM employees e
JOIN departments d ON d.dept_id = e.dept_id;23. Левое внешнее соединение
SELECT e.emp_name, d.dept_name
FROM employees e
LEFT JOIN departments d ON d.dept_id = e.dept_id;24. Правое внешнее соединение
SELECT e.emp_name, d.dept_name
FROM employees e
RIGHT JOIN departments d ON d.dept_id = e.dept_id;25. Полное внешнее соединение
SELECT e.emp_name, d.dept_name
FROM employees e
FULL OUTER JOIN departments d ON d.dept_id = e.dept_id;26. Иерархический обход (корни)
SELECT emp_id, emp_name, LEVEL
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR emp_id = manager_id;27. Стабильная сортировка ветвей
SELECT emp_id, emp_name, LEVEL
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR emp_id = manager_id
ORDER SIBLINGS BY emp_name;28. Путь до узла
SELECT emp_id, SYS_CONNECT_BY_PATH(emp_name,' / ') AS path
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR emp_id = manager_id;29. ROW_NUMBER для ранжирования
SELECT emp_id, salary,
ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rn
FROM employees;30. RANK и DENSE_RANK
SELECT emp_id, salary,
RANK() OVER (ORDER BY salary DESC) AS rnk,
DENSE_RANK() OVER (ORDER BY salary DESC) AS drnk
FROM employees;31. Оконная сумма по отделу
SELECT emp_id, dept_id, salary,
SUM(salary) OVER (PARTITION BY dept_id ORDER BY emp_id) AS run_sum
FROM employees;32. LAG/LEAD для сравнения соседей
SELECT emp_id, salary,
LAG(salary) OVER (ORDER BY emp_id) AS prev_sal,
LEAD(salary) OVER (ORDER BY emp_id) AS next_sal
FROM employees;33. LISTAGG в одну строку
SELECT dept_id,
LISTAGG(emp_name, ', ') WITHIN GROUP (ORDER BY emp_name) AS employees_list
FROM employees
GROUP BY dept_id;34. PIVOT — годы по колонкам
SELECT *
FROM sales
PIVOT ( SUM(amount) FOR year IN (2023, 2024, 2025) );35. UNPIVOT — разворот по атрибутам
SELECT product_id, metric, val
FROM sales_metrics
UNPIVOT ( val FOR metric IN (q1, q2, q3, q4) );36. CTE через WITH
WITH recent AS (
SELECT * FROM orders WHERE order_date >= DATE '2025-01-01'
)
SELECT order_id, customer_id FROM recent;37. Рекурсивный WITH (дерево отделов)
WITH dept_tree (dept_id, parent_id, lvl) AS (
SELECT dept_id, parent_id, 1 FROM departments WHERE parent_id IS NULL
UNION ALL
SELECT d.dept_id, d.parent_id, t.lvl+1
FROM departments d JOIN dept_tree t ON d.parent_id = t.dept_id
)
SELECT * FROM dept_tree;38. JSON_VALUE в колонках
SELECT order_id,
JSON_VALUE(jdoc, '$.customer.id') AS customer_id,
JSON_VALUE(jdoc, '$.amount') AS amount
FROM orders_json;39. JSON_TABLE для реляционного вида
SELECT jt.id, jt.qty
FROM orders o,
JSON_TABLE(o.jdoc, '$.lines[*]'
COLUMNS ( id NUMBER PATH '$.id', qty NUMBER PATH '$.qty')) jt;40. UNION для объединения наборов
SELECT id, name FROM a
UNION
SELECT id, name FROM b;Еще 20 примеров.
41. UNION ALL без удаления дублей
SELECT id, name FROM a
UNION ALL
SELECT id, name FROM b;42. INTERSECT — пересечение
SELECT id FROM a
INTERSECT
SELECT id FROM b;43. MINUS — разность множеств
SELECT id FROM a
MINUS
SELECT id FROM b;44. Функции строк: SUBSTR/INSTR
SELECT emp_name,
SUBSTR(emp_name,1,3) AS prefix,
INSTR(emp_name,' ') AS space_pos
FROM employees;45. Регулярные выражения в фильтре
SELECT email
FROM users
WHERE REGEXP_LIKE(email, '^[^@]+@example\.com$');46. Извлечение компонент даты
SELECT hire_date,
EXTRACT(YEAR FROM hire_date) AS y,
EXTRACT(MONTH FROM hire_date) AS m
FROM employees;47. Форматирование даты в строку
SELECT TO_CHAR(order_date, 'YYYY-MM-DD') AS d
FROM orders;48. Арифметика дат (плюс 7 дней)
SELECT order_id, order_date, order_date + 7 AS eta
FROM orders;49. Числовое форматирование
SELECT amount, TO_CHAR(amount,'FM999G999D00') AS formatted
FROM payments;50. DECODE для кодов
SELECT code, DECODE(code,'A','Alpha','B','Beta','Other') AS label
FROM dict;51. Коррелированный подзапрос с агрегатом
SELECT e.emp_id, e.salary,
(SELECT AVG(salary) FROM employees x WHERE x.dept_id = e.dept_id) AS dept_avg
FROM employees e;52. EXISTS для проверки наличия
SELECT d.dept_id, d.dept_name
FROM departments d
WHERE EXISTS (SELECT 1 FROM employees e WHERE e.dept_id = d.dept_id);53. SAMPLE — случайная доля строк
SELECT *
FROM big_table SAMPLE (5);54. FOR UPDATE блокировка строк
SELECT *
FROM orders
WHERE status = 'NEW'
FOR UPDATE;55. FOR UPDATE SKIP LOCKED для очередей
SELECT *
FROM tasks
WHERE status = 'NEW'
FOR UPDATE SKIP LOCKED;56. NOWAIT при блокировке
SELECT *
FROM tasks
WHERE status = 'NEW'
FOR UPDATE NOWAIT;57. Подставной столбец с константой
SELECT emp_id, 'ACTIVE' AS status
FROM employees;58. Ограничение столбцов через выражение
SELECT emp_id, salary * 12 AS salary_year
FROM employees;59. Скалярная функция в списке вывода
SELECT emp_id, UPPER(emp_name) AS up_name
FROM employees;60. Агрегаты без группировки (итоги)
SELECT COUNT(*) AS cnt, MIN(salary) AS min_sal, MAX(salary) AS max_sal
FROM employees;Еще 20 примеров.
SELECT dept_id
FROM employees
GROUP BY dept_id
HAVING COUNT(*) >= 5;62. ORDER BY по выражению
SELECT emp_id, salary * 12 AS y
FROM employees
ORDER BY y DESC;63. FETCH WITH TIES для «ничего не потерять»
SELECT emp_id, salary
FROM employees
ORDER BY salary DESC
FETCH FIRST 3 ROWS WITH TIES;64. Подзапрос в FROM (inline view)
SELECT t.dept_id, t.cnt
FROM (
SELECT dept_id, COUNT(*) AS cnt
FROM employees
GROUP BY dept_id
) t;65. USING в соединении по одноимённым
SELECT *
FROM a JOIN b USING (id);66. Сортировка с NULLS LAST
SELECT salary
FROM employees
ORDER BY salary NULLS LAST;67. Ограничение по ROWNUM (устаревший паттерн)
SELECT *
FROM (
SELECT * FROM employees ORDER BY salary DESC
)
WHERE ROWNUM <= 10;68. DISTINCT вместе с агрегатами
SELECT COUNT(DISTINCT dept_id) AS dept_cnt
FROM employees;69. Оконное среднее «скользящее»
SELECT ts, val,
AVG(val) OVER (ORDER BY ts ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS mov_avg
FROM metrics;70. GROUPING SETS для нескольких срезов
SELECT dept_id, job, SUM(salary) AS s
FROM employees
GROUP BY GROUPING SETS ((dept_id, job), (dept_id), ());71. ROLLUP для иерархических итогов
SELECT dept_id, job, SUM(salary) AS s
FROM employees
GROUP BY ROLLUP (dept_id, job);72. CUBE для всех комбинаций
SELECT region, dept_id, SUM(salary) AS s
FROM employees
GROUP BY CUBE (region, dept_id);73. MINUS с ORDER BY во внешней оболочке
SELECT * FROM (
SELECT id FROM a
MINUS
SELECT id FROM b
) t
ORDER BY id;74. INTERSECT с FETCH FIRST
SELECT * FROM (
SELECT id FROM a
INTERSECT
SELECT id FROM b
)
FETCH FIRST 5 ROWS ONLY;75. Псевдотаблица DUAL
SELECT 'hello' AS greeting
FROM dual;76. CASE в ORDER BY для кастомной сортировки
SELECT status, created_at
FROM orders
ORDER BY CASE status WHEN 'NEW' THEN 1 WHEN 'PENDING' THEN 2 ELSE 3 END, created_at;77. Все колонки из таблицы
SELECT *
FROM employees;78. Только нужные поля
SELECT emp_id, emp_name, hire_date
FROM employees;79. Псевдонимы для удобного вывода
SELECT emp_name AS name, salary AS sal
FROM employees;80. Арифметика и округление
SELECT emp_id, salary, ROUND(salary * 1.2, 2) AS salary_with_bonus
FROM employees;Еще 20 примеров.
81. DISTINCT для уникальных значений
SELECT DISTINCT dept_id
FROM employees;82. Фильтрация по условию
SELECT emp_id, emp_name
FROM employees
WHERE dept_id = 10 AND salary > 5000;83. Диапазон через BETWEEN
SELECT emp_id, salary
FROM employees
WHERE salary BETWEEN 3000 AND 7000;84. Список значений через IN
SELECT emp_id, dept_id
FROM employees
WHERE dept_id IN (10,20,30);85. Поиск по шаблону (LIKE)
SELECT emp_id, emp_name
FROM employees
WHERE emp_name LIKE 'A%';86. Проверка на NULL
SELECT emp_id, manager_id
FROM employees
WHERE manager_id IS NULL;87. Сортировка по одному полю
SELECT emp_id, emp_name, salary
FROM employees
ORDER BY salary DESC;88. Сортировка по нескольким полям
SELECT emp_id, emp_name, dept_id, salary
FROM employees
ORDER BY dept_id, salary DESC;89. Ограничение выдачи (FETCH FIRST)
SELECT emp_id, salary
FROM employees
ORDER BY salary DESC
FETCH FIRST 10 ROWS ONLY;90. Пагинация через OFFSET/FETCH
SELECT emp_id, emp_name
FROM employees
ORDER BY emp_id
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;91. Агрегация по отделам
SELECT dept_id, AVG(salary) AS avg_sal, COUNT(*) AS cnt
FROM employees
GROUP BY dept_id;92. Фильтр агрегатов (HAVING)
SELECT dept_id, AVG(salary) AS avg_sal
FROM employees
GROUP BY dept_id
HAVING AVG(salary) > 6000;93. Производное поле через CASE
SELECT emp_name,
CASE WHEN salary >= 6000 THEN 'HIGH' ELSE 'NORMAL' END AS band
FROM employees;94. Подзапрос в IN
SELECT emp_id, emp_name
FROM employees
WHERE dept_id IN (SELECT dept_id FROM departments WHERE region = 'EU');95. EXISTS с корреляцией
SELECT d.dept_id, d.dept_name
FROM departments d
WHERE EXISTS (
SELECT 1 FROM employees e
WHERE e.dept_id = d.dept_id
AND e.salary > 8000
);96. Скалярный подзапрос в списке вывода
SELECT emp_id, (SELECT dept_name FROM departments d WHERE d.dept_id = e.dept_id) AS dept_name
FROM employees e;97. Перекрёстное соединение
SELECT a.*, b.*
FROM a
CROSS JOIN b;98. Внутреннее соединение по ключу
SELECT e.emp_name, d.dept_name
FROM employees e
JOIN departments d ON d.dept_id = e.dept_id;99. Левое внешнее соединение
SELECT e.emp_name, d.dept_name
FROM employees e
LEFT JOIN departments d ON d.dept_id = e.dept_id;100. Правое внешнее соединение
SELECT e.emp_name, d.dept_name
FROM employees e
RIGHT JOIN departments d ON d.dept_id = e.dept_id;Частые ошибки и подводные камни
- Неявные преобразования. Разные типы в сравнениях приводят к неожиданным планам; приводите явно.
- Фильтры и индексы. Функции над колонками в
WHEREмогут «ломать» индекс; используйте функциональные индексы. - Группировка. Всё, что не агрегат — должно быть в
GROUP BY. - Ограничение выдачи. Для стабильной пагинации используйте детерминированный
ORDER BYвместе сOFFSET/FETCH.
Альтернативы
JSON_TABLE/XMLTABLE— когда источник — документы.MODEL— расчёты в табличной форме (продвинутые сценарии).- Рекурсивный
WITH— альтернатива иерархическим запросам для произвольных правил обхода.
Заключение
SELECT — сердце SQL. Стройте только необходимые колонки, пишите селективные условия, фиксируйте порядок и используйте оконные функции там, где это упрощает логику.
Документация
Следующая статья:
ZONE в Oracle SQL — как использовать часовые пояса