Использование CROSS JOIN для задач поиска пересечений в исторических данных
Время прочтения: 5 мин.
CROSS JOIN (или полное соединение таблиц без условий) — декартова перемножение множеств. Говоря простым языком — для каждого варианта первого множества будет сопоставлены все варианты второго множества.
Данным типом соединения нужно пользоваться с осторожностью, т.к. виртуальная таблица занимает n*m объема данных в ОЗУ (для соединения 3-х таблиц — n*m*t, и т.д.). Тем не менее, при правильном использовании данный тип соединения таблиц может решать достаточно трудоемкие задачи, такие как — нахождение пересечений в исторических данных. Примером данной задачи может являться: недопущение автоматического распределения заявок клиента на андеррайтера с родственными связями.
Структура таблиц ниже представленных примеров следующая:
Допустим: клиент Сидоров Степан Павлович подал заявку на кредит. На некотором этапе рассмотрения потребовался анализ платежеспособности клиента андеррайтером.
Заявка автоматически распределилась на сотрудника Петрова Екатерина Павловна.
На первый взгляд ничего подозрительного нет — в ФИО людей совпадает только отчество, что является широко распространенной ситуацией.
Однако, при детальном анализе выясняется, что девичья фамилия андеррайтера и клиента совпадают (Сидорова / Сидоров).
SELECT fh.fio_history_id , fh.fio_id , fh.person_id , ln.lname, fn.fname, mn.mname , fh.actual FROM fio_history fh INNER JOIN fio f ON fh.fio_id = f.fio_id INNER JOIN lname ln ON f.lname_id = ln.lname_id INNER JOIN fname fn ON f.fname_id = fn.fname_id INNER JOIN mname mn ON f.mname_id = mn.mname_id WHERE person_id IN (1, 5) ORDER BY fh.actual DESC;
В таком случае заявка клиента должна была распределиться на другого сотрудника, чтобы решение, вынесенное по заявке, было не предвзятым.
Для решения данной задачи можно использовать простой запрос с CROSS JOIN:
SELECT results.* FROM (SELECT underwriter. person_id as u_person_id , underwriter.fio_id as u_fio_id , underwriter.lname as u_lname , client.person_id as c_person_id , client.fio_id as c_fio_id , client.lname as c_lname , CASE WHEN underwriter.lname_id = client.lname_id OR underwriter.lname_stem = client.lname_stem THEN 1 ELSE 0 END as is_equal_lnames FROM (-- Андеррайтер "Петрова Екатерина Павловна" SELECT fh.person_id, fh.fio_id, ln.lname_id, ln.lname , regexp_replace(upper(ln.lname), '(А|ИЙ|АЯ)$', '')) as lname_stem FROM fio_history fh INNER JOIN fio f ON fh.fio_id = f.fio_id INNER JOIN lname ln ON f.lname_id = ln.lname_id WHERE fh.person_id = 1) underwriter CROSS JOIN (-- Клиент "Сидоров Степан Павлович" SELECT fh.person_id, fh.fio_id, ln.lname_id, ln.lname , regexp_replace(upper(ln.lname), '(А|ИЙ|АЯ)$', '')) as lname_stem FROM fio_history fh INNER JOIN fio f ON fh.fio_id = f.fio_id INNER JOIN lname ln ON f.lname_id = ln.lname_id WHERE fh.person_id = 5) client) results WHERE results.is_equal_lnames = 1;
В результате было найдено одно пересечение, что может указывать на родственные связи по Фамилии.
Данный пример является достаточно простым в проверке, т.к. родственные связи находятся в пределах одного поколения.
Но, что если андеррайтер не должен обрабатывать заявки не только своих братьев, сестер, родителей и детей, но также членов семей братьев и сестер своих супругов.
В данной ситуации подход остается тот же, увеличивается только лишь количество проверяемых субъектов.
Пусть будет ситуация аналогичная предыдущей: клиент Иванов Алексей Николаевич оформляет заявку на кредит, которая впоследствии распределяется на андеррайтера Петров Юрий Александрович.
На первый взгляд, очевидно, что люди не являются родственниками.
Нам необходимо проверить всех ближайших родственников клиента со всеми ближайшими родственниками андеррайтера (предполагается, что родственные связи записаны в других справочниках; для простоты представления примера идентификаторы person_id указаны явным образом).
SELECT fh.fio_history_id , fh.fio_id , fh.person_id , ln.lname, fn.fname, mn.mname , fh.actual FROM fio_history fh INNER JOIN fio f ON fh.fio_id = f.fio_id INNER JOIN lname ln ON f.lname_id = ln.lname_id INNER JOIN fname fn ON f.fname_id = fn.fname_id INNER JOIN mname mn ON f.mname_id = mn.mname_id WHERE fh.person_id IN (1, 2, 3, 4) ORDER BY actual DESC;
Чтобы обнаружить родственные связи между двумя разными семьями необходимо выполнить рекурсивное декартова перемножение множеств имен каждого из супругов.
WITH people_info AS ( SELECT person_id , fio_id , NULL as relative_person_id , NULL as relative_fio_id FROM fio_history UNION ALL SELECT pinf. person_id , pinf.fio_id , fh.person_id as other_person_id , fh.fio_id as other_fio_id FROM fio_history fh CROSS JOIN people_info pinf WHERE pinf.relative_person_id IS NULL )
SELECT results.* FROM (SELECT underwriter.person_id as u_person_id , underwriter.fio_id as u_fio_id , underwriter.relative_person_id as u_relative_person_id , underwriter.relative_fio_id as u_relative_fio_id , underwriter.lname as u_lname , client.person_id as c_person_id , client.fio_id as c_fio_id , client.relative_person_id as c_relative_person_id , client.relative_fio_id as c_relative_fio_id , client.lname as c_lname , CASE WHEN underwriter.lname_id = client.lname_id OR underwriter.lname_stem = client.lname_stem THEN 1 ELSE 0 END as is_equal_lnames FROM (-- Андеррайтер "Петров Юрий Александрович" SELECT pinf. person_id, pinf.fio_id , pinf.relative_person_id, pinf.relative_fio_id, ln.lname_id, ln.lname , regexp_replace(upper(ln.lname), '(А|ИЙ|АЯ)$', '')) as lname_stem FROM people_info pinf INNER JOIN fio f ON pinf.relative_fio_id = f.fio_id INNER JOIN lname ln ON f.lname_id = ln.lname_id WHERE pinf.relative_person_id IS NOT NULL AND pinf.person_id IN (4) AND pinf.relative_person_id IN (1, 4)) underwriter CROSS JOIN (-- Клиент "Иванов Алексей Николаевич" SELECT pinf.person_id, pinf.fio_id , pinf.relative_person_id, pinf.relative_fio_id, ln.lname_id, ln.lname , regexp_replace(upper(ln.lname), '(А|ИЙ|АЯ)$', '')) as lname_stem FROM people_info pinf INNER JOIN fio f ON pinf.relative_fio_id = f.fio_id INNER JOIN lname ln ON f.lname_id = ln.lname_id WHERE pinf.relative_person_id IS NOT NULL AND pinf.person_id IN (3) AND pinf.relative_person_id IN (2, 3)) client) results WHERE results.is_equal_lnames = 1;
Таким образом, родственные связи клиента и андеррайтера были обнаружены между их женами, которые являются родными сестрами.
Задачи, где может потребоваться проверка исторических данных, могут быть самыми разнообразными, и во многих случаях CROSS JOIN может упростить их решение.
Полное соединение · Loginom Help
Перекрестное соединение (SQL-аналог: CROSS JOIN )При полном соединении ( Пример: Для примера возьмем две таблицы. Главная таблица — Персона, присоединяемая — Город. Главная таблица:
Присоединяемая таблица:
Результирующая таблица:
FULL JOIN )При полном соединении (
При таком соединении необходимо сопоставление ключевых полей. Пример: Для примера возьмем две таблицы. Главная таблица — Персона, присоединяемая — Город. Главная таблица:
Присоединяемая таблица:
Результирующая таблица:
При любом соединении (
|
перекрестное соединение — Power Query
Редактировать
Твиттер LinkedIn Фейсбук Электронное письмо
- Статья
- 2 минуты на чтение
Перекрестное соединение — это тип соединения, который возвращает декартово произведение строк из таблиц в соединении. Другими словами, он объединяет каждую строку из первой таблицы с каждой строкой из второй таблицы.
В этой статье на практическом примере показано, как выполнить перекрестное соединение в Power Query.
Примеры таблиц ввода и вывода
В этом примере примерами исходных таблиц являются:
Продукт : Таблица со всеми общими продуктами, которые вы продаете.
Цвета : Таблица со всеми вариациями продуктов в виде цветов, которые вы можете иметь в своем инвентаре.
Цель состоит в том, чтобы выполнить операцию перекрестного соединения с этими двумя таблицами, чтобы создать список всех уникальных продуктов, которые вы можете иметь в своем инвентаре, как показано в следующей таблице. Эта операция необходима, потому что таблица Product содержит только общее название продукта и не дает уровня детализации, необходимого для просмотра возможных вариантов продукта (например, цвета).
Выполнение перекрестного соединения
Чтобы выполнить операцию перекрестного соединения в Power Query, сначала перейдите к Товар табл. На вкладке Добавить столбец на ленте выберите Пользовательский столбец . Дополнительные сведения: Добавление пользовательского столбца
В диалоговом окне Пользовательский столбец введите любое имя в поле Имя нового столбца и введите Цвета
в поле Формула пользовательского столбца .
Важно
Если в имени запроса есть пробелы, например Цвета продукта , текст, который необходимо ввести в поле Раздел формулы пользовательского столбца должен следовать синтаксису #"Имя запроса"
. Для Цвета продукта необходимо ввести #"Цвета продукта"
.
Вы можете проверить название своих запросов на панели Параметры запроса в правой части экрана или на панели Запросы на левой стороне.
После выбора OK в диалоговом окне Пользовательский столбец в таблицу добавляется новый столбец. В заголовке нового столбца выберите Разверните , чтобы развернуть содержимое этого вновь созданного столбца, а затем выберите OK .
После выбора OK вы достигнете цели создания таблицы со всеми возможными комбинациями Продукт и Цвет .
Обратная связь
Отправить и просмотреть отзыв для
Этот продукт Эта страница
Просмотреть все отзывы о странице
SQL CROSS JOIN с примерами
В этой статье мы изучим концепцию SQL CROSS JOIN и подкрепим наши знания простыми примерами, которые объясняются иллюстрациями.
Введение
CROSS JOIN используется для создания парной комбинации каждой строки первой таблицы с каждой строкой второй таблицы. Этот тип соединения также известен как декартово соединение.
Предположим, что мы сидим в кофейне и решили заказать завтрак. Вскоре мы посмотрим на меню и начнем думать, какое сочетание еды и напитков может быть вкуснее. Наш мозг получит этот сигнал и начнет генерировать все комбинации еды и питья.
На следующем изображении показаны все комбинации меню, которые может генерировать наш мозг. SQL CROSS JOIN работает аналогично этому механизму, поскольку создает все парные комбинации строк таблиц, которые будут объединены.
«Пожалуйста, не волнуйтесь, даже если вы чувствуете себя немного голодным сейчас, вы можете есть все, что захотите, после прочтения нашей статьи».
Основная идея CROSS JOIN заключается в том, что она возвращает декартово произведение соединенных таблиц. В следующем совете мы кратко объясним декартово произведение;
Совет: Что такое декартово произведение?
Декартово произведение — это операция умножения в теории множеств, которая генерирует все упорядоченные пары заданных множеств. Предположим, что A — это множество, а элементами являются {a,b}, а B — это множество, а элементами являются {1,2,3}. Декартово произведение этих двух A и B обозначается AxB, и результат будет примерно следующим.
AxB = {(а, 1), (а, 2), (а, 3), (б, 1), (б, 2), (б, 3)}
Синтаксис
Синтаксис CROSS JOIN в SQL будет выглядеть следующим образом:
SELECT ColumnName_1, ColumnName_2, ColumnName_N FROM [Table_1] CROSS JOIN [Table_2] |
Или мы можем использовать следующий синтаксис вместо предыдущего. Этот синтаксис не включает ключевое слово CROSS JOIN; только мы будем размещать таблицы, которые будут объединены после предложения FROM и разделены запятой.
SELECT ColumnName_1, ColumnName_2, ColumnName_N ИЗ [Table_1],[Table_2] |
Набор результатов не меняется ни для одного из этих синтаксисов. Кроме того, мы должны отметить один момент, касающийся CROSS JOIN. В отличие от INNER JOIN, LEFT JOIN и FULL OUTER JOIN, CROSS JOIN не требует условия соединения.
Пример перекрестного соединения SQL:
В этом примере мы снова рассмотрим пример меню завтрака, о котором мы упоминали в предыдущей части статьи. Во-первых, мы создадим таблицы с двумя примерами, которые будут содержать названия напитков и блюд. После этого мы заполним их некоторыми образцами данных.
С помощью следующего запроса мы выполним эти два шага:
1 2 3 4 5 6 7 8 9 10 | CREATE TABLE Meals(MealName VARCHAR(100)) CREATE TABLE Drinks(DrinkName VARCHAR(100)) INSERT INTO Drinks VALUES('Апельсиновый сок'), ('Чай'), ('Кофе') ВСТАВИТЬ В Блюда ЗНАЧЕНИЯ('Омлет'), ('Яичница'), ('Колбаса') SELECT * ИЗ Блюд; ВЫБЕРИТЕ * ИЗ Напитков |
Следующий запрос соединит таблицу Meals and Drinks с помощью ключевого слова CROSS JOIN , и мы получим все парные комбинации названий блюд и напитков.
SELECT * FROM Еда CROSS JOIN Напитки |
Изображение ниже иллюстрирует принцип работы CROSS JOIN.
В то же время мы можем использовать следующий запрос, чтобы получить тот же набор результатов с альтернативным синтаксисом без CROSS JOIN.
ВЫБЕРИТЕ * ИЗ Блюда ,Напитки |
Совет: Количество строк набора результатов будет равно произведению количества строк таблиц, которые будут объединены. В примере с меню завтрака количество строк в таблице «Питание» равно 3, а количество строк в таблице «Напитки» равно 3, поэтому количество строк набора результатов можно найти с помощью следующего вычисления.
3 (Количество строк в таблице питания) x 3 (Количество строк в таблице напитков) = (Количество строк результатов) .
Функция CONCAT_WS поможет объединить выражения столбцов. Таким образом, мы можем создать более значимый набор результатов меню завтрака.
ВЫБЕРИТЕ CONCAT_WS('-',MealName,DrinkName) AS MenuList ОТ Блюда CROSS JOIN Напитки |
SQL CROSS JOIN и вопросы производительности
Запросы SQL, содержащие ключевое слово CROSS JOIN, могут быть очень дорогостоящими. Мы пытаемся сказать, что эти запросы могут потреблять больше ресурсов и вызывать проблемы с производительностью. Для следующего запроса мы проанализируем план выполнения с помощью ApexSQL Plan. В сгенерированном фактическом плане выполнения мы увидим оператор вложенных циклов, и когда мы наведем указатель мыши на этот оператор, появится всплывающее окно с подробностями.
В этом окне нам бросается в глаза предупреждающее сообщение. Сообщение «No Join Predicate» указывает, что этот запрос может столкнуться с проблемами производительности. По этой причине оптимизатор запросов предупреждает нас об этой потенциальной проблеме. Вкратце, когда мы решаем использовать CROSS JOIN в каком-либо запросе, мы должны учитывать количество таблиц, которые будут объединены. Например, когда мы выполняем ПЕРЕКРЕСТНОЕ СОЕДИНЕНИЕ двух таблиц, и если первая содержит 1000 строк, а вторая — 1000 строк, количество строк в результирующем наборе будет равно 1 000 000 строк.
Совет: ПЕРЕКРЕСТНОЕ СОЕДИНЕНИЕ может быть реализовано только с вложенными циклами, поэтому следующие запросы вернут ошибку, если мы заставим оптимизатор запросов использовать другие типы соединений.
1 2 3 4 5 6 7 8 9 | ВЫБЕРИТЕ * ИЗ Блюда ПЕРЕКРЕСТНОЕ СОЕДИНЕНИЕ Напитки ВАРИАНТ (СОЕДИНЕНИЕ ОБЪЕДИНЕНИЕМ)
GO
SELECT * FROM Meals CROSS JOIN Напитки ОПЦИЯ (HASH JOIN ) |
Заключение
В этой статье мы подробно изучили основы SQL CROSS JOIN, а также упомянули соображения производительности CROSS JOIN.