JOIN в Oracle SQL или как объединять таблицы и находить связанные данные

🟢 JOIN в Oracle SQL. Введение

Давай по‑честному: без JOIN жизнь в Oracle SQL была бы серой. Именно соединения позволяют связывать таблицы логикой предметной области — от заказов и клиентов до сложных аналитических витрин. Я покажу простым языком, как мыслить связями, не перегружая запросы и не теряя производительность.

Синтаксис

SELECT t1.col1,t2.col2
FROM t1
INNER JOIN t2 ON t2.fk=t1.pk
-- Варианты: LEFT/RIGHT/FULL OUTER,CROSS,NATURAL,USING(...)
-- Советы: ключи равенства держи в ON/USING, фильтры результата — в WHERE

Где используют

  • Операционная отчётность: связать факты продаж со справочниками клиентов и товаров.
  • Аналитика: собрать витрину из фактов и измерений с аккуратной денормализацией.
  • Качество данных: находить «висячие» ссылки и аномальные многие‑ко‑многим.
  • Оптимизация: баланс условий между ON и WHERE, предагрегация и умные подсказки.

Коротко о лучших практиках

  • Определи «драйвер» выборки — таблицу, задающую зерно.
  • Связи равенства — в ON/USING, фильтры — в WHERE.
  • Выводи только нужные столбцы — это делает план легче и быстрее.
  • Предагрегируй с GROUP BY перед сложными связями «многие‑ко‑многим».
  • Осторожнее с FULL OUTER: полезно, но затратно.

100 примеров

1. Связь фактов и справочника по ключу

SELECT o.order_id,o.amount,c.customer_name
FROM orders o
INNER JOIN customers c ON c.customer_id=o.customer_id

2. Левое соединение когда не у всех есть профиль

SELECT u.user_id,u.email,p.phone
FROM users u
LEFT OUTER JOIN profiles p ON p.user_id=u.user_id

3. Правое при акценте на справочнике

SELECT d.dept_id,d.dept_name,e.emp_name
FROM employees e
RIGHT OUTER JOIN departments d ON d.dept_id=e.dept_id

4. Полное объединение для сверки остатка

SELECT a.sku,a.qty AS a_qty,b.qty AS b_qty
FROM stock_a a
FULL OUTER JOIN stock_b b ON b.sku=a.sku

5. Сведение многих к одному через USING

SELECT s.sale_id,s.amount,d.dim_name
FROM sales s
INNER JOIN dims d USING(dim_id)

6. Декартово произведение для генерации сетки

SELECT d.dt,h.hh
FROM calendar_days d
CROSS JOIN hours h

7. Самосоединение для поиска менеджера

SELECT e.emp_name,m.emp_name AS manager
FROM employees e
LEFT OUTER JOIN employees m ON m.emp_id=e.manager_id

8. Фильтр после соединения в WHERE

SELECT o.order_id,o.status,c.city
FROM orders o
INNER JOIN customers c ON c.customer_id=o.customer_id
WHERE o.status='PAID'

9. Соединение с подзапросом предагрегации

SELECT c.customer_id,c.customer_name,t.total
FROM customers c
LEFT OUTER JOIN(
SELECT customer_id,SUM(amount) AS total
FROM orders
GROUP BY customer_id
) t ON t.customer_id=c.customer_id

10. Соединение по нескольким условиям

SELECT f.id,f.region,d.rate
FROM fact f
INNER JOIN dict_rates d ON d.region=f.region AND d.year=f.year

11. USING когда имена ключей совпадают

SELECT s.sale_id,s.amount,p.product_name
FROM sales s
INNER JOIN products p USING(product_id)

12. Сопоставление дат по диапазону

SELECT b.booking_id,r.room_no
FROM bookings b
INNER JOIN rooms r ON r.hotel_id=b.hotel_id AND b.dt BETWEEN r.dt_from AND r.dt_to

13. Слияние клиента с последним заказом

SELECT c.customer_id,c.customer_name,o.order_id,o.amount
FROM customers c
LEFT OUTER JOIN(
SELECT order_id,customer_id,amount,ROW_NUMBER() OVER(PARTITION BY customer_id ORDER BY order_date DESC) AS rn
FROM orders
) o ON o.customer_id=c.customer_id AND o.rn=1

14. Связь по составному ключу

SELECT l.country,l.city,w.temp
FROM locations l
INNER JOIN weather w ON w.country=l.country AND w.city=l.city

15. Обогащение транзакций валютным курсом

SELECT t.id,t.amt,t.ccy,r.rate
FROM trx t
LEFT OUTER JOIN rates r ON r.ccy=t.ccy AND r.rate_date=t.trx_date

16. Связь фактов и календаря по дате

SELECT f.id,f.amount,cal.week_of_year
FROM fact_sales f
LEFT OUTER JOIN dim_calendar cal ON cal.dt=f.sale_date

17. Атрибутика заказа из нескольких таблиц

SELECT o.order_id,c.customer_name,p.product_name
FROM orders o
INNER JOIN customers c ON c.customer_id=o.customer_id
INNER JOIN products p ON p.product_id=o.product_id

18. Сведение many‑to‑many через предагрегацию

SELECT t.tag,COUNT(*) AS posts
FROM(
SELECT pt.post_id,t.tag
FROM post_tags pt
INNER JOIN tags t ON t.tag_id=pt.tag_id
) t
GROUP BY t.tag

19. Сопоставление адресов с регионами по префиксу

SELECT a.addr_id,a.zip,r.region
FROM addresses a
LEFT OUTER JOIN zip_regions r ON SUBSTR(a.zip,1,3)=r.zip_prefix

20. Подтягиваем статус доставки

SELECT o.order_id,o.amount,sh.status
FROM orders o
LEFT OUTER JOIN shipments sh ON sh.order_id=o.order_id

Еще 20 примеров

21. Слияние чеков с платежами за сутки

SELECT ch.id,ch.total,p.payment_method
FROM checks ch
LEFT OUTER JOIN payments p ON p.check_id=ch.id AND TRUNC(p.paid_at)=TRUNC(ch.created_at)

22. Обогащение события юзер‑агентом

SELECT e.event_id,e.path,u.agent
FROM events e
LEFT OUTER JOIN user_agents u ON u.ua_id=e.ua_id

23. Сопоставление сотрудников и городов

SELECT e.emp_id,e.emp_name,c.city_name
FROM employees e
LEFT OUTER JOIN cities c ON c.city_id=e.city_id

24. Сверка справочников по полному объединению

SELECT NVL(a.code,b.code) AS code,a.name AS a_name,b.name AS b_name
FROM dict_a a
FULL OUTER JOIN dict_b b ON b.code=a.code

25. Соединение с in‑line view для быстрого фильтра

SELECT o.order_id,o.amount
FROM orders o
INNER JOIN(SELECT order_id FROM fraud WHERE flag='Y') f ON f.order_id=o.order_id

26. Поиск лишних связей через левое и NULL

SELECT p.product_id
FROM products p
LEFT OUTER JOIN product_images i ON i.product_id=p.product_id
WHERE i.product_id IS NULL

27. Синхронизация остатков склада

SELECT s.sku,s.qty AS system_qty,r.qty AS real_qty
FROM stock_system s
LEFT OUTER JOIN stock_real r ON r.sku=s.sku

28. Связь по ключу и дате актуальности

SELECT k.id,k.value,h.note
FROM keys k
LEFT OUTER JOIN key_history h ON h.id=k.id AND k.dt BETWEEN h.valid_from AND h.valid_to

29. Разворот контактов клиента

SELECT c.customer_id,c.customer_name,ph.phone,em.email
FROM customers c
LEFT OUTER JOIN phones ph ON ph.customer_id=c.customer_id
LEFT OUTER JOIN emails em ON em.customer_id=c.customer_id

30. Самосопоставление — коллеги из одного отдела

SELECT a.emp_name AS e1,b.emp_name AS e2
FROM employees a
INNER JOIN employees b ON b.dept_id=a.dept_id AND b.emp_id<>a.emp_id

31. Справочник валют к транзакциям по дате начала

SELECT t.id,t.ccy,r.rate
FROM trx t
LEFT OUTER JOIN rates r ON r.ccy=t.ccy AND r.valid_from<=t.trx_date

32. Связка склада и ассортимента

SELECT s.sku,p.product_name,s.qty
FROM stock s
INNER JOIN products p ON p.sku=s.sku

33. Соотнесение заказов и счетов

SELECT o.order_id,inv.invoice_id,inv.total
FROM orders o
LEFT OUTER JOIN invoices inv ON inv.order_id=o.order_id

34. Атрибутика платежа через две таблицы

SELECT p.payment_id,c.customer_name,m.method_name
FROM payments p
INNER JOIN customers c ON c.customer_id=p.customer_id
INNER JOIN methods m ON m.method_id=p.method_id

35. Выбор последних статусов по пользователю

SELECT u.user_id,u.email,s.status
FROM users u
LEFT OUTER JOIN(
SELECT user_id,status,ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY changed_at DESC) rn
FROM statuses
) s ON s.user_id=u.user_id AND s.rn=1

36. Соединение с подсчётом заказов в подзапросе

SELECT c.customer_id,c.customer_name,t.cnt
FROM customers c
LEFT OUTER JOIN(
SELECT customer_id,COUNT(*) cnt
FROM orders
GROUP BY customer_id
) t ON t.customer_id=c.customer_id

37. Сопоставление позиций и чеков

SELECT i.item_id,i.price,ch.check_id
FROM items i
INNER JOIN checks ch ON ch.check_id=i.check_id

38. Сведение по телефону или email

SELECT c.customer_id,c.customer_name,co.contact
FROM customers c
LEFT OUTER JOIN contacts co ON co.customer_id=c.customer_id AND co.primary_flag='Y'

39. Сопоставление IP с геобазой по сети

SELECT l.ip,g.country
FROM logs l
LEFT OUTER JOIN geo g ON l.ip BETWEEN g.ip_from AND g.ip_to

40. Аналитика заказов с типом клиента

SELECT o.order_id,o.amount,ct.type_name
FROM orders o
LEFT OUTER JOIN customer_types ct ON ct.type_id=o.type_id

Еще 20 примеров

41. Детализация суммы по товарам

SELECT o.order_id,p.product_name,oi.qty,oi.qty*p.price AS line_total
FROM orders o
INNER JOIN order_items oi ON oi.order_id=o.order_id
INNER JOIN products p ON p.product_id=oi.product_id

42. Связка событий и каналов

SELECT e.event_id,ch.channel_name
FROM events e
LEFT OUTER JOIN channels ch ON ch.channel_id=e.channel_id

43. Сопоставление действий с реферальной кампанией

SELECT a.action_id,c.campaign_name
FROM actions a
LEFT OUTER JOIN campaigns c ON c.campaign_id=a.campaign_id

44. Фокус на справочнике и возможном отсутствии фактов

SELECT p.product_id,p.product_name,oi.qty
FROM products p
LEFT OUTER JOIN order_items oi ON oi.product_id=p.product_id

45. Выборка, где нет соответствия в справочнике

SELECT t.code
FROM trx_types t
LEFT OUTER JOIN dict_types d ON d.code=t.code
WHERE d.code IS NULL

46. Проверка целостности внешних ключей

SELECT o.order_id
FROM orders o
LEFT OUTER JOIN customers c ON c.customer_id=o.customer_id
WHERE c.customer_id IS NULL

47. Сопоставление версий документов

SELECT d.doc_id,v.version_no,v.author
FROM docs d
LEFT OUTER JOIN versions v ON v.doc_id=d.doc_id

48. Сводка продаж по категориям

SELECT cat.category_name,SUM(oi.qty*p.price) AS revenue
FROM categories cat
LEFT OUTER JOIN products p ON p.category_id=cat.category_id
LEFT OUTER JOIN order_items oi ON oi.product_id=p.product_id
GROUP BY cat.category_name

49. Прайс и актуальная скидка на дату

SELECT p.product_id,p.product_name,pr.price,dc.percent
FROM products p
LEFT OUTER JOIN prices pr ON pr.product_id=p.product_id AND pr.price_date=DATE '2025-09-01'
LEFT OUTER JOIN discounts dc ON dc.product_id=p.product_id AND dc.valid_from<=DATE '2025-09-01'

50. Связка платежей и статей ДДС

SELECT pay.payment_id,gl.gl_name
FROM payments pay
LEFT OUTER JOIN gl_dict gl ON gl.gl_id=pay.gl_id

51. Обогащение лога справочником ошибок

SELECT l.err_id,l.message,d.err_text
FROM error_log l
LEFT OUTER JOIN error_dict d ON d.err_id=l.err_id

52. Клиент и его основной адрес

SELECT c.customer_id,c.customer_name,a.city,a.street
FROM customers c
LEFT OUTER JOIN addresses a ON a.customer_id=c.customer_id AND a.primary_flag='Y'

53. Сопоставление транзакций и терминалов

SELECT t.trx_id,t.amount,term.terminal_name
FROM trx t
LEFT OUTER JOIN terminals term ON term.terminal_id=t.terminal_id

54. Фокус на всех датах календаря даже без фактов

SELECT cal.dt,NVL(f.amount,0) AS amt
FROM dim_calendar cal
LEFT OUTER JOIN fact_daily f ON f.dt=cal.dt

55. Связка пользователей и ролей

SELECT u.user_id,u.email,r.role_name
FROM users u
LEFT OUTER JOIN user_roles ur ON ur.user_id=u.user_id
LEFT OUTER JOIN roles r ON r.role_id=ur.role_id

56. Обогащение колл‑логов маршрутом

SELECT c.call_id,r.route_name
FROM calls c
LEFT OUTER JOIN routes r ON r.route_id=c.route_id

57. Соотнесение платежей и возмещений

SELECT pay.payment_id,ref.refund_id,ref.amount
FROM payments pay
LEFT OUTER JOIN refunds ref ON ref.payment_id=pay.payment_id

58. Склейка доп. атрибутов товара

SELECT p.product_id,p.product_name,a.attr_name,a.attr_value
FROM products p
LEFT OUTER JOIN product_attrs a ON a.product_id=p.product_id

59. Сопоставление тикетов и агентов

SELECT t.ticket_id,a.agent_name
FROM tickets t
LEFT OUTER JOIN agents a ON a.agent_id=t.agent_id

60. Агрегация после присоединения справочников

SELECT c.city_name,COUNT(*) AS orders_cnt
FROM orders o
INNER JOIN customers cu ON cu.customer_id=o.customer_id
INNER JOIN cities c ON c.city_id=cu.city_id
GROUP BY c.city_name

Еще 20 примеров

61. Выборка сотрудников без отдела

SELECT e.emp_id,e.emp_name
FROM employees e
LEFT OUTER JOIN departments d ON d.dept_id=e.dept_id
WHERE d.dept_id IS NULL

62. Сравнение прайсов двух поставщиков

SELECT NVL(a.sku,b.sku) AS sku,a.price AS price_a,b.price AS price_b
FROM price_a a
FULL OUTER JOIN price_b b ON b.sku=a.sku

63. Связка заказов и статусов оплаты

SELECT o.order_id,o.amount,p.status
FROM orders o
LEFT OUTER JOIN pay_status p ON p.order_id=o.order_id

64. Подтягиваем страну по IP с диапазонами

SELECT l.id,g.country
FROM logins l
LEFT OUTER JOIN geoip g ON l.ip_num BETWEEN g.ip_from AND g.ip_to

65. Матчинг клиентов по email

SELECT a.id AS a_id,b.id AS b_id,a.email
FROM src_a a
INNER JOIN src_b b ON LOWER(b.email)=LOWER(a.email)

66. Синхронизация каталога и остатков

SELECT p.sku,p.product_name,st.qty
FROM products p
LEFT OUTER JOIN stock st ON st.sku=p.sku

67. Слияние KPI и целей

SELECT kpi.metric,kpi.value,goal.target
FROM kpi
LEFT OUTER JOIN goals goal ON goal.metric=kpi.metric

68. Аналитика: корзина и купоны

SELECT cart.user_id,coupon.code
FROM carts cart
LEFT OUTER JOIN coupons coupon ON coupon.coupon_id=cart.coupon_id

69. Сопоставление курса по ближайшей дате

SELECT t.id,t.ccy,r.rate
FROM trx t
LEFT OUTER JOIN(
SELECT ccy,rate_date,rate,ROW_NUMBER() OVER(PARTITION BY ccy ORDER BY rate_date DESC) rn
FROM rates
) r ON r.ccy=t.ccy AND r.rn=1

70. Связка задач и исполнителей

SELECT t.task_id,u.user_name
FROM tasks t
LEFT OUTER JOIN users u ON u.user_id=t.assignee_id

71. Детализация заказов и позиций

SELECT o.order_id,oi.item_id,oi.qty
FROM orders o
INNER JOIN order_items oi ON oi.order_id=o.order_id

72. Сопоставление городов и регионов

SELECT c.city_name,r.region_name
FROM cities c
LEFT OUTER JOIN regions r ON r.region_id=c.region_id

73. Обогащение логов устройствами

SELECT l.event_id,d.device_type
FROM logs l
LEFT OUTER JOIN devices d ON d.device_id=l.device_id

74. Разделение платёжных проводок по счетам

SELECT p.posting_id,acc.account_no
FROM postings p
LEFT OUTER JOIN accounts acc ON acc.account_id=p.account_id

75. Достижения игрока и уровни

SELECT a.player_id,lvl.level_name
FROM achievements a
LEFT OUTER JOIN levels lvl ON lvl.level_id=a.level_id

76. Связка просмотров и контента

SELECT v.view_id,c.title
FROM views v
LEFT OUTER JOIN content c ON c.content_id=v.content_id

77. Присоединение группы лояльности

SELECT c.customer_id,c.customer_name,l.group_name
FROM customers c
LEFT OUTER JOIN loyalty l ON l.customer_id=c.customer_id

78. Обогащение заявок статусом KYC

SELECT a.app_id,k.status
FROM applications a
LEFT OUTER JOIN kyc k ON k.app_id=a.app_id

79. Соотнесение поездок и водителей

SELECT r.ride_id,d.driver_name
FROM rides r
LEFT OUTER JOIN drivers d ON d.driver_id=r.driver_id

80. Гистограмма заказов по категории

SELECT cat.category_name,COUNT(*) cnt
FROM categories cat
LEFT OUTER JOIN products p ON p.category_id=cat.category_id
LEFT OUTER JOIN order_items oi ON oi.product_id=p.product_id
GROUP BY cat.category_name

Еще 20 примеров

81. Связка клиентов и последних визитов

SELECT c.customer_id,c.customer_name,v.visit_at
FROM customers c
LEFT OUTER JOIN(
SELECT customer_id,MAX(visit_at) AS visit_at
FROM visits
GROUP BY customer_id
) v ON v.customer_id=c.customer_id

82. Сопоставление с ближайшим складом по городу

SELECT o.order_id,w.wh_name
FROM orders o
LEFT OUTER JOIN warehouses w ON w.city_id=o.city_id

83. Связка транзакций и категорий расходов

SELECT t.trx_id,cat.cat_name
FROM trx t
LEFT OUTER JOIN categories cat ON cat.cat_id=t.cat_id

84. Матчинг по нормализованному телефону

SELECT p.person_id,c.contact_id
FROM persons p
INNER JOIN contacts c ON REGEXP_REPLACE(c.phone,'\D')=REGEXP_REPLACE(p.phone,'\D')

85. Разруливание дубликатов по ключу

SELECT s.id,src.source_name
FROM sources s
LEFT OUTER JOIN src_map src ON src.id=s.id

86. Обогащение заказов менеджером

SELECT o.order_id,m.manager_name
FROM orders o
LEFT OUTER JOIN managers m ON m.manager_id=o.manager_id

87. Сопоставление платежей и банков

SELECT p.payment_id,b.bank_name
FROM payments p
LEFT OUTER JOIN banks b ON b.bank_id=p.bank_id

88. Связка визитов и каналов привлечения

SELECT v.visit_id,ch.channel_name
FROM visits v
LEFT OUTER JOIN channels ch ON ch.channel_id=v.channel_id

89. Стримы и авторы

SELECT s.stream_id,a.author_name
FROM streams s
LEFT OUTER JOIN authors a ON a.author_id=s.author_id

90. Профили и аватары

SELECT p.profile_id,a.url
FROM profiles p
LEFT OUTER JOIN avatars a ON a.profile_id=p.profile_id

91. Материализация витрины с атрибутами

CREATE TABLE mart_orders AS
SELECT o.order_id,o.amount,c.customer_name,p.product_name
FROM orders o
INNER JOIN customers c ON c.customer_id=o.customer_id
INNER JOIN products p ON p.product_id=o.product_id

92. Аналитика просмотров по типу контента

SELECT ct.type_name,COUNT(*) cnt
FROM content c
INNER JOIN content_types ct ON ct.type_id=c.type_id
GROUP BY ct.type_name

93. Сопоставление сотрудников и должностей

SELECT e.emp_id,e.emp_name,j.job_name
FROM employees e
LEFT OUTER JOIN jobs j ON j.job_id=e.job_id

94. Обогащение транзакций географией

SELECT t.id,geo.country,geo.city
FROM trx t
LEFT OUTER JOIN geo ON geo.geo_id=t.geo_id

95. Проверка висячих ссылок на метод оплаты

SELECT o.order_id
FROM orders o
LEFT OUTER JOIN methods m ON m.method_id=o.method_id
WHERE m.method_id IS NULL

96. Сверка остатков между системами

SELECT NVL(a.sku,b.sku) AS sku,a.qty AS a_qty,b.qty AS b_qty
FROM inv_a a
FULL OUTER JOIN inv_b b ON b.sku=a.sku

97. Доставка и курьеры

SELECT d.delivery_id,c.courier_name
FROM deliveries d
LEFT OUTER JOIN couriers c ON c.courier_id=d.courier_id

98. Кампании и объявления

SELECT ad.ad_id,cmp.campaign_name
FROM ads ad
LEFT OUTER JOIN campaigns cmp ON cmp.campaign_id=ad.campaign_id

99. Клиент, заказ, товар — тройка

SELECT c.customer_name,o.order_id,p.product_name
FROM customers c
INNER JOIN orders o ON o.customer_id=c.customer_id
INNER JOIN products p ON p.product_id=o.product_id

100. Финальный срез для отчёта

SELECT d.dt,SUM(oi.qty*p.price) AS revenue
FROM dim_calendar d
LEFT OUTER JOIN orders o ON TRUNC(o.order_date)=d.dt
LEFT OUTER JOIN order_items oi ON oi.order_id=o.order_id
LEFT OUTER JOIN products p ON p.product_id=oi.product_id
GROUP BY d.dt

Документация

Oracle SQL Language Reference — Joins


🧩 Заключение

JOIN — один из самых мощных инструментов SQL. Он позволяет соединять таблицы и строить сложные отчёты.
Понимание разных типов JOIN’ов — критически важно для аналитики и разработки сложных систем на Oracle SQL.


🔜 Следующая статья:

INNER в Oracle SQL — что такое INNER JOIN и как он работает под капотом


Понравилась статья? Поделиться с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest
0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии