Сценарії поєднання таблиць за допомогою JOIN із додатковими умовами AND та OR
| 🌐 Цей документ доступний українською та англійською мовами. Використовуйте перемикач у правому верхньому куті, щоб змінити версію. |
1. Загальний опис
Операція <ext:join> дозволяє поєднувати таблиці за певними умовами. Використовується при створенні критеріїв пошуку всередині тегу <ext:createSearchCondition> для отримання необхідних даних у зведених таблицях.
- Є 3 основні типи поєднання таблиць за допомогою JOIN:
-
-
INNER JOIN — Перетин даних двох таблиць. Наприклад,
<ext:join type="inner">. -
LEFT JOIN — вивід даних з першої таблиці (зліва) та приєднання даних другої таблиці (справа), де це можливо. Наприклад,
<ext:join type="left">. -
RIGHT JOIN — протилежний до LEFT JOIN. Наприклад,
<ext:join type="right">.
-
Операцію <ext:join> можна використовувати із додатковими умовами and та or, які визначаються в рамках тегу <ext:condition> як значення атрибута logicOperator.
2. Приклади використання
Розглянемо приклади використання умови JOIN у критеріях пошуку та додаткові умови AND та OR в рамках рольової моделі та її окремого випадку із застосуванням довідників кодифікатора КАТОТТГ.
2.1. Передумови
Створіть дві таблиці для використання у критеріях пошуку та поєднання за допомогою JOIN.
-
<createTable tableName="katottg">— таблиця, що містить коди КАТОТТГ.Приклад. Таблиця "katottg"
<changeSet id="table katottg" author="registry_owner"> <createTable tableName="katottg" ext:historyFlag="true" remarks="katottg"> <column name="katottg_id" type="UUID" defaultValueComputed="uuid_generate_v4()" remarks="Ідентифікатор katottg"> <constraints nullable="false" primaryKey="true" primaryKeyName="pk_katottg_id"/> </column> <column name="code" type="TEXT" remarks="Код"> <constraints nullable="true"/> </column> <column name="name" type="TEXT" remarks="Назва"> <constraints nullable="true"/> </column> <column name="category" type="TEXT" remarks="Категорія"> <constraints nullable="true"/> </column> <column name="level" type="INT"> <constraints nullable="false"/> </column> <column name="katottg_parent_id" type="UUID"> <constraints nullable="true" foreignKeyName="fk_katottg_parent" referencedTableName="katottg" referencedColumnNames="katottg_id"/> </column> </createTable> <addUniqueConstraint tableName="katottg" columnNames="code"/> </changeSet> -
<createTable tableName="katottg_category"— таблиця, що містить категорії кодів КАТОТТГ.Приклад. Таблиця "katottg_category"
<changeSet id="table katottg_category" author="registry_owner"> <createTable tableName="katottg_category" ext:historyFlag="true" remarks="katottg_category"> <column name="katottg_category_id" type="UUID" defaultValueComputed="uuid_generate_v4()" remarks="Ідентифікатор"> <constraints nullable="false" primaryKey="true" primaryKeyName="pk_katottg_category_id"/> </column> <column name="code" type="TEXT" remarks="Код"> <constraints nullable="false"/> </column> <column name="name" type="TEXT" remarks="Назва"> <constraints nullable="true"/> </column> </createTable> <addUniqueConstraint tableName="katottg_category" columnNames="code"/> </changeSet>
2.2. Сценарії
Створимо критерій пошуку get_regions_or_city_regions. На основі цього критерію пошуку буде створено ендпоінт у фабриці даних, який зможе повертати список усіх областей України, а також міста зі спеціальним статусом, їх коди КАТОТТГ, а також категорію коду КАТОТТГ, при виконанні певних умов запита, а саме:
-
Об’єднати таблиці за допомогою
JOINта додатковою умовоюAND:<ext:condition logicOperator="and" columnName="k.category" operator="eq" value="'K'"/> -
Об’єднати таблиці за допомогою
JOINта додатковою умовоюOR:<ext:condition logicOperator="or" columnName="k.category" operator="eq" value="cat.code"> <ext:condition logicOperator="and" columnName="k.category" operator="ne" value="'K'"/> <ext:condition logicOperator="and" columnName="k.level" operator="eq" value="'1'"/> </ext:condition>
Залежно від умови, яку ви зазначаєте у запиті, формується й відповідний результат. Тобто формується вибірка з певної кількості записів, об’єднаних в одній зведеній таблиці.
2.2.1. Використання INNER JOIN без додаткових умов
<ext:createSearchCondition name="get_regions_or_citi_regions">
<ext:table name="katottg" alias="k">
<ext:column name="katottg_id" />
<ext:column name="name" alias="name_region" searchType="startsWith" />
<ext:column name="category" />
</ext:table>
<ext:table name="katottg_category" alias="cat">
<ext:column name="name" alias="name_category" />
<ext:column name="code" />
</ext:table>
<ext:join type="inner">
<ext:left alias="k">
<ext:column name="category" />
</ext:left>
<ext:right alias="cat">
<ext:column name="code" />
</ext:right>
</ext:join>
</ext:createSearchCondition>
- На виході Liquibase генерує наступний SQL-запит:
-
Приклад 2. SQL-запит. Використання INNER JOIN без додаткових умов
CREATE OR REPLACE VIEW registry.get_regions_or_citi_regions_v AS SELECT k.katottg_id, k.name AS name_region, cat.name AS name_category, cat.code FROM katottg k JOIN katottg_category cat ON k.category = cat.code
2.2.2. Використання INNER JOIN із додатковою умовою AND
<ext:createSearchCondition name="get_regions_or_citi_regions">
<ext:table name="katottg" alias="k">
<ext:column name="katottg_id" />
<ext:column name="name" alias="name_region" searchType="startsWith" />
<ext:column name="category" />
</ext:table>
<ext:table name="katottg_category" alias="cat">
<ext:column name="name" alias="name_category" />
<ext:column name="code" />
</ext:table>
<ext:join type="inner">
<ext:left alias="k">
<ext:column name="category" />
</ext:left>
<ext:right alias="cat">
<ext:column name="code" />
</ext:right>
<ext:condition logicOperator="and" columnName="k.category" operator="eq" value="'K'"/>
</ext:join>
</ext:createSearchCondition>
- На виході Liquibase генерує наступний SQL-запит:
-
Приклад 4. SQL-запит. Використання INNER JOIN з умовою AND
CREATE OR REPLACE VIEW registry.get_regions_or_citi_regions_v AS SELECT k.katottg_id, k.name AS name_region, cat.name AS name_category, cat.code FROM katottg k JOIN katottg_category cat ON k.category = cat.code AND k.category = 'K' :: text; - Результат виконання запита буде таким:
-
Якщо об’єднати таблиці за допомогою
JOINіз додатковою умовоюAND, то ви отримаєте вибірку лише з 2-х записів:
Зображення 1. Результат запита за умовами JOIN + AND
2.2.3. Використання INNER JOIN із додатковою умовою OR
<ext:createSearchCondition name="get_regions_or_citi_regions">
<ext:table name="katottg" alias="k">
<ext:column name="katottg_id" />
<ext:column name="name" alias="name_region" searchType="startsWith" />
<ext:column name="category" />
</ext:table>
<ext:table name="katottg_category" alias="cat">
<ext:column name="name" alias="name_category" />
<ext:column name="code" />
</ext:table>
<ext:join type="inner">
<ext:left alias="k">
<ext:column name="category" />
</ext:left>
<ext:right alias="cat">
<ext:column name="code" />
</ext:right>
<ext:condition logicOperator="or" columnName="k.category" operator="eq" value="cat.code">
<ext:condition logicOperator="and" columnName="k.category" operator="ne" value="'K'"/>
<ext:condition logicOperator="and" columnName="k.level" operator="eq" value="'1'"/>
</ext:condition>
</ext:join>
</ext:createSearchCondition>
- На виході Liquibase генерує наступний SQL-запит:
-
Приклад 6. SQL-запит. Використання INNER JOIN з умовою OR
CREATE OR REPLACE VIEW registry.get_regions_or_citi_regions_v AS SELECT k.katottg_id, k.name AS name_region, cat.name AS name_category, cat.code FROM katottg k JOIN katottg_category cat ON k.category = cat.code OR k.category = cat.code AND k.category <> 'K'::text AND k.level = 1; - Результат виконання запита буде таким:
-
Якщо об’єднати таблиці за допомогою
JOINіз додатковою умовоюOR, то ви отримаєте вибірку з 25 записів:
Зображення 2. Результат запита за умовами JOIN + OR
2.2.4. Використання INNER JOIN із додатковими умовами AND та OR
<ext:createSearchCondition name="get_regions_or_citi_regions">
<ext:table name="katottg" alias="k">
<ext:column name="katottg_id" />
<ext:column name="name" alias="name_region" searchType="startsWith" />
<ext:column name="category" />
</ext:table>
<ext:table name="katottg_category" alias="cat">
<ext:column name="name" alias="name_category" />
<ext:column name="code" />
</ext:table>
<ext:join type="inner">
<ext:left alias="k">
<ext:column name="category" />
</ext:left>
<ext:right alias="cat">
<ext:column name="code" />
</ext:right>
<ext:condition logicOperator="and" columnName="k.category" operator="eq" value="'K'"/>
<ext:condition logicOperator="or" columnName="k.category" operator="eq" value="cat.code">
<ext:condition logicOperator="and" columnName="k.category" operator="ne" value="'K'"/>
<ext:condition logicOperator="and" columnName="k.level" operator="eq" value="'1'"/>
</ext:condition>
</ext:join>
</ext:createSearchCondition>
- На виході Liquibase генерує наступний SQL-запит:
-
Приклад 8. SQL-запит. Використання INNER JOIN з умовами AND та OR
CREATE OR REPLACE VIEW registry.get_regions_or_citi_regions_v AS SELECT k.katottg_id, k.name AS name_region, cat.name AS name_category, cat.code FROM katottg k JOIN katottg_category cat ON k.category = cat.code AND k.category = 'K' :: text OR k.category = cat.code AND k.category <> 'K'::text AND k.level = 1; - Результат виконання запита буде таким:
-
Якщо об’єднати таблиці за допомогою
JOINіз додатковими умовамиANDтаOR, то ви отримаєте вибірку з 27 записів:
Зображення 3. Результат запита за умовами JOIN + AND + OR
3. Інші приклади використання
Функціональне розширення liquibase дозволяє додавати довільні умови до основних умов <ext:join>.
3.1. Використання LEFT JOIN з однією додатковою умовою OR
Наприклад, для операції поєднання двох таблиць cities та katottg_dictionary, за умови що katottg дорівнює або level4 або add_level, в <ext:join> використовуються <ext:left> та <ext:right> для визначення основної умови — katottg=level4, та <ext:condition> для визначення додаткової умови — katottg=add_level та методу логічного поєднання умов — OR.
<changeSet author="registry owner" id="or join">
<ext:createSearchCondition name="cities_4_or_5_level">
<ext:table name="cities" alias="ci">
<ext:column name="city_id" />
<ext:column name="name" searchType="startsWith" />
<ext:column name="katottg" searchType="equal" />
</ext:table>
<ext:table name="katottg_dictionary" alias="kd">
<ext:column name="name" alias="name_dict" />
</ext:table>
<ext:join type="left">
<ext:left alias="ci">
<ext:column name="katottg" />
</ext:left>
<ext:right alias="kd">
<ext:column name="level4" />
</ext:right>
<ext:condition logicOperator="or" columnName="ci.katottg" operator="eq" value="kd.add_level" />
</ext:join>
</ext:createSearchCondition>
</changeSet>
- На виході Liquibase генерує наступний SQL-запит:
-
Приклад 10. SQL-запит. Використання LEFT JOIN з умовою OR
SELECT ci.city_id, ci.name, ci.katottg, kd.name AS name_dict FROM cities AS ci LEFT JOIN katottg_dictionary AS kd ON (ci.katottg = kd.level4) or (ci.katottg = kd.add_level);
3.2. Використання LEFT JOIN з декількома додатковими умовами AND та OR
Також за допомогою <ext:condition> можна моделювати складніші умови поєднання таблиць.
Наприклад, для тих самих таблиць cities та katottg_dictionary, якщо умова з’єднання — katottg дорівнює level4, коли category не дорівнює 'B', або katottg дорівнює add_level, коли category дорівнює 'B', то схема критерію пошуку виглядатиме наступним чином:
<changeSet author="registry owner" id="or join by category">
<ext:createSearchCondition name="cities_4_or_5_level_by_category">
<ext:table name="cities" alias="ci">
<ext:column name="city_id" />
<ext:column name="name" searchType="startsWith" />
<ext:column name="katottg" searchType="equal" />
</ext:table>
<ext:table name="katottg_dictionary" alias="kd">
<ext:column name="name" alias="name_dict" />
</ext:table>
<ext:join type="left">
<ext:left alias="ci">
<ext:column name="katottg" />
</ext:left>
<ext:right alias="kd">
<ext:column name="level4" />
</ext:right>
<ext:condition logicOperator="and" columnName="kd.category" operator="ne" value="'B'">
<ext:condition logicOperator="or" columnName="ci.katottg" operator="eq" value="kd.add_level" />
<ext:condition logicOperator="and" columnName="kd.category" operator="eq" value="'B'"/>
</ext:condition>
</ext:join>
</ext:createSearchCondition>
</changeSet>
- На виході Liquibase генерує наступний SQL-запит:
-
Приклад 12. SQL-запит. Використання LEFT JOIN з декількома додатковими умовами AND та OR
SELECT ci.city_id, ci.name, ci.katottg, kd.name AS name_dict FROM cities AS ci LEFT JOIN katottg_dictionary AS kd ON (ci.katottg = kd.level4) and (kd.category = 'B') or ((ci.katottg = kd.add_level) and (kd.category <> 'B'));
|
Зверніть увагу, що вкладені умови Для цього прикладу групування не є обов’язковим: без дужок код виконається так само як і з дужками, оскільки умови Зверніть увагу на цю особливість для можливого використання за інших умов. |