SlideShare uma empresa Scribd logo
1 de 25
Тайны оператора JOIN
Проблемы и их решение
Содержание
• Что такое оператор соединения?
• CROSS JOIN
• INNER JOIN
• OUTER JOIN
• Множественные соединения
• Вопросы-ответы
Оператор соединения
- оператор алгебры, две таблицы на входе, таблица
на выходе
- результат широкий, т.к. содержит все колонки
исходных таблиц
- соединение происходит по условию
- количество строк в результате меняется
Пример, INNER JOIN
Users Payments
UserID UserName
1 Ivan
2 Pit
3 John
UserID Date Amount
1 01.01.2013 1000
1 01.02.2013 2000
2 01.01.2013 1000
UserID UserName UserID Date Amount
1 Ivan 1 01.01.2013 1000
1 Ivan 1 01.01.2013 2000
2 Pit 2 01.01.2013 1000
Пример, INNER JOIN
SELECT *
FROM Users
JOIN Payments
ON Users.UserID = Payments.UserID
CROSS JOIN
Вырожденый случай соединения, без условия. То же
самое, что декартово перемножение.
A = {1, 2}
B = {A, B, C}
A CROSS JOIN B
A x B = {(1,A), (1,B), (1, C), (2,A), (2,B), (2, C)}
Опасная штука, т.к. может создавать результаты
огромных размеров.
INNER JOIN
Выводит совпадающие по заданому условию строки из
двух таблиц. Условия можно писать в WHERE и в ON,
нет практической разницы где это делать.
SELECT * FROM Users JOIN Payments
ON Users.UserID = Payments.UserID
WHERE Users.UserID = 1
SELECT * FROM Users JOIN Payments
ON Users.UserID = Payments.UserID
AND Users.UserID = 1
INNER JOIN
Общее правило - в ON мы пишем условия для
соединения таблиц, в WHERE - все остальные условия
SELECT * FROM Users JOIN Payments
ON Users.UserID = Payments.UserID
WHERE Users.UserID = 1
OUTER JOIN
Необходимость таких соединений становится понятна
если попытаться написать классический запрос вида
"вернуть всех пользователей без платежей".
Внешнее соединение возвращает все строки из одной
таблицы, плюс добавляет строки из другой таблицы,
если выполняется условие соединения. В результате у
нас как минимум столько же строк как в одной таблице.
Есть LEFT JOIN, RIGHT JOIN и FULL JOIN. LEFT JOIN -
все строки из левой таблицы,RIGHT JOIN - все строки
из правой, FULL - все строки из обоих таблиц.
Пример, OUTER JOIN
Users Payments
UserID UserName
1 Ivan
2 Pit
3 John
UserID Date Amount
1 01.01.2013 1000
1 01.02.2013 2000
2 01.01.2013 1000
UserID UserName UserID Date Amount
1 Ivan 1 01.01.2013 1000
1 Ivan 1 01.01.2013 2000
2 Pit 2 01.01.2013 1000
3 John NULL NULL NULL
Пример, OUTER JOIN
SELECT Users.*
FROM Users
LEFT JOIN Payments
ON Users.UserID = Payments.UserID
WHERE
Payments.UserID IS NULL
OUTER JOIN, трюк 1
• Есть разница, где писать условия, в
WHERE или ON. То, что написано в ON
"выполнится" до соединения, в WHERE -
после. Поэтому проверку на IS NULL
можно написать только в WHERE, в этот
момент NULL уже есть в результате
соединения.
WHERE
Payments.UserID IS NULL
OUTER JOIN, трюк 2
• Часто нужно сначала отфильтровать
правую таблицу (для LEFT JOIN), а потом
соединять. В этом случае условие можно
записать в ON.
SELECT Users.*
FROM Users LEFT JOIN Payments
ON Users.UserID = Payments.UserID
and Payments.Date = '2013-01-10'
WHERE
Payments.UserID IS NULL
OUTER JOIN, трюк 3
• Условие к левой таблице в ON будет
проигнорировано, таков алгоритм LEFT
JOIN, он всегда вернет все записи из
левой таблицы
FROM Users LEFT JOIN Payments
ON Users.UserID = Payments.UserID
and Users.UserID = 1
OUTER JOIN, трюк 4.1
• Если используется LEFT JOIN и проверка на IS
NULL, то условия в WHERE не должны
конфликтовать. Сервер ничего не вычисляя
возвращает NULL в этом случае:
SELECT Users.*
FROM Users
LEFT JOIN Payments
ON Users.UserID = Payments.UserID
WHERE
Payments.UserID IS NULL
and Payments.Date = '2013-01-10'
OUTER JOIN, трюк 4.2
• Менее очевидный случай. Запрос
работает так, словно условия UserID IS NULL
нет вообще.
FROM Users LEFT JOIN Payments
ON Users.UserID = Payments.UserID
WHERE
(Payments.UserID IS NULL
or Payments.Date = '2013-01-10')
and Payments.Amount > 1000
OUTER JOIN, трюк 4.2
Так и получается, если упростить
логическое выражение
(Payments.UserID IS NULL
or Payments.Date = '2013-01-10')
and Payments.Amount > 1000
A = Payments.UserID IS NULL
B = Payments.Date = '2013-01-10
C = Payments.Amount > 1000
(A + B)*C = A*C + B*C
A*C = Payments.UserID IS NULL and Payments.Amount > 1000 == FALSE
Множественные соединения
Три и более таблицы во FROM.
Правило 1: INNER JOIN безопасны с точки
зрения логики.
Порядок соединения определяется
оптимизатором, записывать можно в
произвольном порядке.
A JOIN B JOIN C = C JOIN B JOIN A
Множественные соединения
Правило 2: OUTER JOIN коварны
Обрабатываются в порядке записи.
Классическая задача - вернуть данные из зависимых
таблиц для всех пользователей. Интуитивное решение:
FROM Users
LEFT JOIN Payments
ON Users.UserID = Payments.UserID
JOIN PaymentDetail
ON Payments.PaymentID = ...
Множественные соединения
В результате не будет пользователей, у которых нет
платежей, т.к. соединения выполняются попарно, после
первого соединения они будут в результате, после
второго - исчезнут, т.к. у них все поля из Payments -
NULL, в том числе те, по которым присоединяется
третья таблица.
Сервер знает об этом, и обрабатывает такое
соединение как INNER JOIN.
Множественные соединения
Интуитивное решение:
FROM Users
LEFT JOIN Payments
ON Users.UserID = Payments.UserID
LEFT JOIN PaymentDetail
ON Payments.PaymentID = ...
Работает, но не эффективно, и неправильно, если есть
платежи без деталей. Мы хотели информацию по всем
пользователям независимо от наличия платежей,
платежи без деталей нам не интересны.
Множественные соединения
Можно поставить OUTER JOIN последним оператором:
FROM Payments
JOIN PaymentDetail
ON Payments.PaymentID = ...
RIGHT JOIN Users
ON Users.UserID = Payments.UserID
Если запрос сложный, то это может быть непросто.
Более наглядно использовать скобки.
Множественные соединения
FROM Users
LEFT JOIN
(Payments JOIN PaymentDetail
ON Payments.PaymentID = ...
)
ON Users.UserID = Payments.UserID
Скобки в такой записи не обязательны, они нужны
только для облегчения понимания логики запроса. На
самом деле важен только порядок, в котором записаны
ON
Множественные соединения
FROM Users
LEFT JOIN Payments
JOIN PaymentDetail
ON Payments.PaymentID = ...
ON Users.UserID = Payments.UserID
Порядок записи ON не произвольный, это chiatric
relation. Первый - последний, второй - предпоследний,
третий - третий с конца и т.д.
Вопросы - ответы
Рекомендуемая литература:
Itzik Ben-Gan
Inside Microsoft SQL Server 2008: T-SQL Querying

Mais conteúdo relacionado

Mais de IT Weekend

7 Tools for the Product Owner
7 Tools for the Product Owner 7 Tools for the Product Owner
7 Tools for the Product Owner IT Weekend
 
Hacking your Doorbell
Hacking your DoorbellHacking your Doorbell
Hacking your DoorbellIT Weekend
 
An era of possibilities, a window in time
An era of possibilities, a window in timeAn era of possibilities, a window in time
An era of possibilities, a window in timeIT Weekend
 
Web services automation from sketch
Web services automation from sketchWeb services automation from sketch
Web services automation from sketchIT Weekend
 
REST that won't make you cry
REST that won't make you cryREST that won't make you cry
REST that won't make you cryIT Weekend
 
Как договариваться с начальником и заказчиком: выбираем нужный протокол общения
Как договариваться с начальником и заказчиком: выбираем нужный протокол общенияКак договариваться с начальником и заказчиком: выбираем нужный протокол общения
Как договариваться с начальником и заказчиком: выбираем нужный протокол общенияIT Weekend
 
Обзор программы SAP HANA Startup Focus
Обзор программы SAP HANA Startup FocusОбзор программы SAP HANA Startup Focus
Обзор программы SAP HANA Startup FocusIT Weekend
 
World of Agile: Kanban
World of Agile: KanbanWorld of Agile: Kanban
World of Agile: KanbanIT Weekend
 
Risk Management
Risk ManagementRisk Management
Risk ManagementIT Weekend
 
«Spring Integration as Integration Patterns Provider»
«Spring Integration as Integration Patterns Provider»«Spring Integration as Integration Patterns Provider»
«Spring Integration as Integration Patterns Provider»IT Weekend
 
Cutting edge of Machine Learning
Cutting edge of Machine LearningCutting edge of Machine Learning
Cutting edge of Machine LearningIT Weekend
 
Parallel Programming In Modern World .NET Technics
Parallel Programming In Modern World .NET TechnicsParallel Programming In Modern World .NET Technics
Parallel Programming In Modern World .NET TechnicsIT Weekend
 
Parallel programming in modern world .net technics shared
Parallel programming in modern world .net technics   sharedParallel programming in modern world .net technics   shared
Parallel programming in modern world .net technics sharedIT Weekend
 
Maximize Effectiveness of Human Capital
Maximize Effectiveness of Human CapitalMaximize Effectiveness of Human Capital
Maximize Effectiveness of Human CapitalIT Weekend
 
“Using C#/.NET – “Controversial Topics & Common Mistakes”
“Using C#/.NET – “Controversial Topics & Common Mistakes”“Using C#/.NET – “Controversial Topics & Common Mistakes”
“Using C#/.NET – “Controversial Topics & Common Mistakes”IT Weekend
 
“The anatomy of outsourced automation developer”
“The anatomy of outsourced automation developer”“The anatomy of outsourced automation developer”
“The anatomy of outsourced automation developer”IT Weekend
 
«Організація процесу розробки мобільного застосунку для аутсорсингової команд...
«Організація процесу розробки мобільного застосунку для аутсорсингової команд...«Організація процесу розробки мобільного застосунку для аутсорсингової команд...
«Організація процесу розробки мобільного застосунку для аутсорсингової команд...IT Weekend
 
«From Waterfall to Agile/Scrum: the impact on testing»
«From Waterfall to Agile/Scrum: the impact on testing»«From Waterfall to Agile/Scrum: the impact on testing»
«From Waterfall to Agile/Scrum: the impact on testing»IT Weekend
 

Mais de IT Weekend (20)

7 Tools for the Product Owner
7 Tools for the Product Owner 7 Tools for the Product Owner
7 Tools for the Product Owner
 
Hacking your Doorbell
Hacking your DoorbellHacking your Doorbell
Hacking your Doorbell
 
An era of possibilities, a window in time
An era of possibilities, a window in timeAn era of possibilities, a window in time
An era of possibilities, a window in time
 
Web services automation from sketch
Web services automation from sketchWeb services automation from sketch
Web services automation from sketch
 
Why Ruby?
Why Ruby? Why Ruby?
Why Ruby?
 
REST that won't make you cry
REST that won't make you cryREST that won't make you cry
REST that won't make you cry
 
Как договариваться с начальником и заказчиком: выбираем нужный протокол общения
Как договариваться с начальником и заказчиком: выбираем нужный протокол общенияКак договариваться с начальником и заказчиком: выбираем нужный протокол общения
Как договариваться с начальником и заказчиком: выбираем нужный протокол общения
 
Обзор программы SAP HANA Startup Focus
Обзор программы SAP HANA Startup FocusОбзор программы SAP HANA Startup Focus
Обзор программы SAP HANA Startup Focus
 
World of Agile: Kanban
World of Agile: KanbanWorld of Agile: Kanban
World of Agile: Kanban
 
Risk Management
Risk ManagementRisk Management
Risk Management
 
«Spring Integration as Integration Patterns Provider»
«Spring Integration as Integration Patterns Provider»«Spring Integration as Integration Patterns Provider»
«Spring Integration as Integration Patterns Provider»
 
Cutting edge of Machine Learning
Cutting edge of Machine LearningCutting edge of Machine Learning
Cutting edge of Machine Learning
 
Parallel Programming In Modern World .NET Technics
Parallel Programming In Modern World .NET TechnicsParallel Programming In Modern World .NET Technics
Parallel Programming In Modern World .NET Technics
 
Parallel programming in modern world .net technics shared
Parallel programming in modern world .net technics   sharedParallel programming in modern world .net technics   shared
Parallel programming in modern world .net technics shared
 
Maximize Effectiveness of Human Capital
Maximize Effectiveness of Human CapitalMaximize Effectiveness of Human Capital
Maximize Effectiveness of Human Capital
 
“Using C#/.NET – “Controversial Topics & Common Mistakes”
“Using C#/.NET – “Controversial Topics & Common Mistakes”“Using C#/.NET – “Controversial Topics & Common Mistakes”
“Using C#/.NET – “Controversial Topics & Common Mistakes”
 
“The anatomy of outsourced automation developer”
“The anatomy of outsourced automation developer”“The anatomy of outsourced automation developer”
“The anatomy of outsourced automation developer”
 
«Організація процесу розробки мобільного застосунку для аутсорсингової команд...
«Організація процесу розробки мобільного застосунку для аутсорсингової команд...«Організація процесу розробки мобільного застосунку для аутсорсингової команд...
«Організація процесу розробки мобільного застосунку для аутсорсингової команд...
 
You promise?
You promise?You promise?
You promise?
 
«From Waterfall to Agile/Scrum: the impact on testing»
«From Waterfall to Agile/Scrum: the impact on testing»«From Waterfall to Agile/Scrum: the impact on testing»
«From Waterfall to Agile/Scrum: the impact on testing»
 

Тайны оператора JOIN

  • 2. Содержание • Что такое оператор соединения? • CROSS JOIN • INNER JOIN • OUTER JOIN • Множественные соединения • Вопросы-ответы
  • 3. Оператор соединения - оператор алгебры, две таблицы на входе, таблица на выходе - результат широкий, т.к. содержит все колонки исходных таблиц - соединение происходит по условию - количество строк в результате меняется
  • 4. Пример, INNER JOIN Users Payments UserID UserName 1 Ivan 2 Pit 3 John UserID Date Amount 1 01.01.2013 1000 1 01.02.2013 2000 2 01.01.2013 1000 UserID UserName UserID Date Amount 1 Ivan 1 01.01.2013 1000 1 Ivan 1 01.01.2013 2000 2 Pit 2 01.01.2013 1000
  • 5. Пример, INNER JOIN SELECT * FROM Users JOIN Payments ON Users.UserID = Payments.UserID
  • 6. CROSS JOIN Вырожденый случай соединения, без условия. То же самое, что декартово перемножение. A = {1, 2} B = {A, B, C} A CROSS JOIN B A x B = {(1,A), (1,B), (1, C), (2,A), (2,B), (2, C)} Опасная штука, т.к. может создавать результаты огромных размеров.
  • 7. INNER JOIN Выводит совпадающие по заданому условию строки из двух таблиц. Условия можно писать в WHERE и в ON, нет практической разницы где это делать. SELECT * FROM Users JOIN Payments ON Users.UserID = Payments.UserID WHERE Users.UserID = 1 SELECT * FROM Users JOIN Payments ON Users.UserID = Payments.UserID AND Users.UserID = 1
  • 8. INNER JOIN Общее правило - в ON мы пишем условия для соединения таблиц, в WHERE - все остальные условия SELECT * FROM Users JOIN Payments ON Users.UserID = Payments.UserID WHERE Users.UserID = 1
  • 9. OUTER JOIN Необходимость таких соединений становится понятна если попытаться написать классический запрос вида "вернуть всех пользователей без платежей". Внешнее соединение возвращает все строки из одной таблицы, плюс добавляет строки из другой таблицы, если выполняется условие соединения. В результате у нас как минимум столько же строк как в одной таблице. Есть LEFT JOIN, RIGHT JOIN и FULL JOIN. LEFT JOIN - все строки из левой таблицы,RIGHT JOIN - все строки из правой, FULL - все строки из обоих таблиц.
  • 10. Пример, OUTER JOIN Users Payments UserID UserName 1 Ivan 2 Pit 3 John UserID Date Amount 1 01.01.2013 1000 1 01.02.2013 2000 2 01.01.2013 1000 UserID UserName UserID Date Amount 1 Ivan 1 01.01.2013 1000 1 Ivan 1 01.01.2013 2000 2 Pit 2 01.01.2013 1000 3 John NULL NULL NULL
  • 11. Пример, OUTER JOIN SELECT Users.* FROM Users LEFT JOIN Payments ON Users.UserID = Payments.UserID WHERE Payments.UserID IS NULL
  • 12. OUTER JOIN, трюк 1 • Есть разница, где писать условия, в WHERE или ON. То, что написано в ON "выполнится" до соединения, в WHERE - после. Поэтому проверку на IS NULL можно написать только в WHERE, в этот момент NULL уже есть в результате соединения. WHERE Payments.UserID IS NULL
  • 13. OUTER JOIN, трюк 2 • Часто нужно сначала отфильтровать правую таблицу (для LEFT JOIN), а потом соединять. В этом случае условие можно записать в ON. SELECT Users.* FROM Users LEFT JOIN Payments ON Users.UserID = Payments.UserID and Payments.Date = '2013-01-10' WHERE Payments.UserID IS NULL
  • 14. OUTER JOIN, трюк 3 • Условие к левой таблице в ON будет проигнорировано, таков алгоритм LEFT JOIN, он всегда вернет все записи из левой таблицы FROM Users LEFT JOIN Payments ON Users.UserID = Payments.UserID and Users.UserID = 1
  • 15. OUTER JOIN, трюк 4.1 • Если используется LEFT JOIN и проверка на IS NULL, то условия в WHERE не должны конфликтовать. Сервер ничего не вычисляя возвращает NULL в этом случае: SELECT Users.* FROM Users LEFT JOIN Payments ON Users.UserID = Payments.UserID WHERE Payments.UserID IS NULL and Payments.Date = '2013-01-10'
  • 16. OUTER JOIN, трюк 4.2 • Менее очевидный случай. Запрос работает так, словно условия UserID IS NULL нет вообще. FROM Users LEFT JOIN Payments ON Users.UserID = Payments.UserID WHERE (Payments.UserID IS NULL or Payments.Date = '2013-01-10') and Payments.Amount > 1000
  • 17. OUTER JOIN, трюк 4.2 Так и получается, если упростить логическое выражение (Payments.UserID IS NULL or Payments.Date = '2013-01-10') and Payments.Amount > 1000 A = Payments.UserID IS NULL B = Payments.Date = '2013-01-10 C = Payments.Amount > 1000 (A + B)*C = A*C + B*C A*C = Payments.UserID IS NULL and Payments.Amount > 1000 == FALSE
  • 18. Множественные соединения Три и более таблицы во FROM. Правило 1: INNER JOIN безопасны с точки зрения логики. Порядок соединения определяется оптимизатором, записывать можно в произвольном порядке. A JOIN B JOIN C = C JOIN B JOIN A
  • 19. Множественные соединения Правило 2: OUTER JOIN коварны Обрабатываются в порядке записи. Классическая задача - вернуть данные из зависимых таблиц для всех пользователей. Интуитивное решение: FROM Users LEFT JOIN Payments ON Users.UserID = Payments.UserID JOIN PaymentDetail ON Payments.PaymentID = ...
  • 20. Множественные соединения В результате не будет пользователей, у которых нет платежей, т.к. соединения выполняются попарно, после первого соединения они будут в результате, после второго - исчезнут, т.к. у них все поля из Payments - NULL, в том числе те, по которым присоединяется третья таблица. Сервер знает об этом, и обрабатывает такое соединение как INNER JOIN.
  • 21. Множественные соединения Интуитивное решение: FROM Users LEFT JOIN Payments ON Users.UserID = Payments.UserID LEFT JOIN PaymentDetail ON Payments.PaymentID = ... Работает, но не эффективно, и неправильно, если есть платежи без деталей. Мы хотели информацию по всем пользователям независимо от наличия платежей, платежи без деталей нам не интересны.
  • 22. Множественные соединения Можно поставить OUTER JOIN последним оператором: FROM Payments JOIN PaymentDetail ON Payments.PaymentID = ... RIGHT JOIN Users ON Users.UserID = Payments.UserID Если запрос сложный, то это может быть непросто. Более наглядно использовать скобки.
  • 23. Множественные соединения FROM Users LEFT JOIN (Payments JOIN PaymentDetail ON Payments.PaymentID = ... ) ON Users.UserID = Payments.UserID Скобки в такой записи не обязательны, они нужны только для облегчения понимания логики запроса. На самом деле важен только порядок, в котором записаны ON
  • 24. Множественные соединения FROM Users LEFT JOIN Payments JOIN PaymentDetail ON Payments.PaymentID = ... ON Users.UserID = Payments.UserID Порядок записи ON не произвольный, это chiatric relation. Первый - последний, второй - предпоследний, третий - третий с конца и т.д.
  • 25. Вопросы - ответы Рекомендуемая литература: Itzik Ben-Gan Inside Microsoft SQL Server 2008: T-SQL Querying