Задумывались ли вы, как вы можете выразить предикат, который «чувствует», как в SQL:
|
1
|
WHERE Var1 OR Var2 IN (1, 2, 3) |
/ U / CyBerg90 имеет, на Reddit . Идея состояла в том, чтобы создать предикат, который возвращает истину всякий раз, когда оба значения Var1 и Var2 дают 1, 2 или 3.
Каноническое решение
Каноническим решением, очевидно, было бы записать все это так:
|
1
2
|
WHERE Var1 = 1 OR Var1 = 2 OR Var1 = 3OR Var2 = 1 OR Var2 = 2 OR Var2 = 3 |
Много дублирования, хотя.
Использование предикатов IN
Большинство читателей просто связывают два предиката IN :
|
1
2
|
WHERE Var1 IN (1, 2, 3)OR Var2 IN (1, 2, 3) |
Или умные могут обратить предикаты как таковые, чтобы сформировать эквивалент:
|
1
2
3
|
WHERE 1 IN (Var1, Var2)OR 2 IN (Var1, Var2)OR 3 IN (Var1, Var2) |
Хорошее решение с использованием EXISTS и JOIN
Все предыдущие решения в некоторой степени требуют повторения синтаксиса / выражения. Хотя это может не оказать существенного влияния на производительность, оно может определенно взорваться с точки зрения длины выражения. Лучшие решения (с этой точки зрения) используют предикат EXISTS , создавая специальные наборы, которые не являются пустыми, когда и Var1 и Var2 дают 1, 2 или 3.
Вот существует с JOIN
|
1
2
3
4
5
6
|
WHERE EXISTS ( SELECT 1 FROM (VALUES (Var1), (Var2)) t1(v) JOIN (VALUES (1), (2), (3)) t2(v) ON t1.v = t2.v) |
Это решение создает две таблицы с одним значением, объединяя их по этому значению:
|
1
2
3
4
5
6
7
|
+------+ +------+| t1.v | | t2.v |+------+ +------+| Var1 | | 1 || Var2 | | 2 |+------+ | 3 | +------+ |
Глядя на диаграмму Венна , легко увидеть, как JOIN будет генерировать только те значения из t1 и t2 , которые присутствуют в обоих наборах:
Самое красивое решение с использованием EXISTS и INTERSECT
Тем не менее, люди могут не думать о пересечении множества при чтении JOIN . Так почему бы не использовать фактическое пересечение множеств через INTERSECT ? Вот, на мой взгляд, самое хорошее решение:
|
1
2
3
4
5
6
7
|
WHERE EXISTS ( SELECT v FROM (VALUES (Var1), (Var2)) t1(v) INTERSECT SELECT v FROM (VALUES (1), (2), (3)) t2(v)) |
Заметьте, как длина оператора SQL увеличивается с ростом O(m + n) (или просто O(N) , где m, n = number of values in each set , тогда как исходные решения, использующие IN увеличиваются с O(m * n) (или просто O(N 2 ) ).
INTERSECT Поддержка в популярных RDBMS
INTERSECT широко поддерживается как в стандарте SQL, так и в любой из следующих RDBMS, которые поддерживаются jOOQ :
- CUBRID
- DB2
- дерби
- H2
- HANA
- HSQLDB
- Informix
- Энгр
- оракул
- PostgreSQL
- SQLite
- SQL Server
- Sybase ASE
- Sybase SQL Anywhere
Фактически, следующие базы данных также поддерживают менее часто используемый INTERSECT ALL , который не удаляет повторяющиеся значения из полученных пакетов (см. Также UNION против UNION ALL )
- CUBRID
- PostgreSQL
Счастливого пересекающегося!
| Ссылка: | INTERSECT — недооцененный двусторонний прогноз от нашего партнера по JCG Лукаса Эдера в блоге JAVA, SQL и JOOQ . |
