Оптимизация SQL запроса: удаление дубликатов из LEFT JOIN
Быстрый ответ
Вы можете исключить дубликаты при выполнении LEFT JOIN, применив простой подход с использованием подзапроса и оконной функции ROW_NUMBER()
. Используйте PARTITION BY
для столбца, который вызывает дублирование, и затем отберите строки с высшим приоритетом через условие WHERE
, исключая таким образом дубликаты.
SELECT clean.*
FROM (
SELECT t1.*, ROW_NUMBER() OVER (PARTITION BY t1.duplicate_field ORDER BY t1.preferred_order) AS row_num
FROM left_table t1
LEFT JOIN right_table t2 ON t1.id = t2.foreign_id
) AS clean
WHERE clean.row_num = 1;
Здесь duplicate_field
– это столбец, содержащий дубликаты, а preferred_order
устанавливает порядок, по которому будут оцениваться дублирующиеся строки.
Применение OUTER APPLY
для устранения дублирования
В SQL Server доступна функция OUTER APPLY
, которая для каждой строки левой таблицы выполняет подзапрос. Сочетание OUTER APPLY
с TOP 1
позволяет выбрать только одну строку из правой таблицы, предотвращая тем самым дублирование.
SELECT t1.*, oa.*
FROM left_table t1
OUTER APPLY (
SELECT TOP 1 *
FROM right_table t2
WHERE t1.id = t2.foreign_id
ORDER BY t2.rank_criteria
) oa;
Эффективность ключевого слова DISTINCT
Если ваш запрос относительно прост, и вы хотите устранить дубликаты после выполнения LEFT JOIN, используйте ключевое слово DISTINCT
. Однако стоит обратить внимание на то, что применение DISTINCT
может заметно ухудшить производительность при обработке больших объемов данных.
SELECT DISTINCT t1.*
FROM left_table t1
LEFT JOIN right_table t2 ON t1.id = t2.foreign_id;
Тонкие настройки с применением выборочного соединения
Когда дело доходит до работы с многомерными таблицами, например, при связывании контента с медиа, важно тщательно выбирать столбцы для объединения, чтобы избегать создания дубликатов:
SELECT t1.content_id, t1.title, t2.media_id, t2.url
FROM tbl_Contents t1
LEFT JOIN
(
SELECT media_id, content_id, url, ROW_NUMBER() OVER (PARTITION BY content_id ORDER BY priority DESC) as row_num
FROM tbl_Media
) t2
ON t1.content_id = t2.content_id AND t2.row_num = 1;
Визуализация
Рассмотрим аналогию с очередью в фастфуде:
Очередь (👥): [Боб, Алиса, Тед]
Заказы (🍔📝): [Алиса 🍟, Тед 🌭, Тед 🥤, Алиса 🍔]
LEFT JOIN:
👥💔🍔📝 => [Боб: 🚫, Алиса: 🍟 & 🍔, Тед: 🌭 & 🥤]
# Типично для стандартного LEFT JOIN, что Алиса и Тед "клонируются",
# чтобы отобразить ВСЕ их заказы.
Уникальные заказы:
👥💔🍔📝 => [Боб: 🚫, Алиса: ✅, Тед: ✅]
# В данном случае каждый клиент из левой таблицы (очереди) остается уникальным,
# но все заказы клиента всё равно отображаются.
В этом контексте каждый клиент соответствует одной записи в очереди, а список заказов представляет собой разнообразие доступных предложений.
Управление неожиданными NULL и порядком данных
LEFT JOIN
может привести к появлению неожиданных NULL и хаосу в порядке данных. Для избежания этого примените следующий подход:
SELECT t1.content_id, t1.title, ISNULL(t2.media_id, 'No media') AS media_id
FROM tbl_Contents t1
LEFT JOIN tbl_Media t2 ON t1.content_id = t2.content_id
ORDER BY t1.content_id, t2.priority;
Обеспечение целостности данных
Ваши запросы должны извлекать все соответствующие строки из левой таблицы без дублирования, даже когда в правой таблице есть NULL:
SELECT t1.*, COALESCE(t2.attribute, 'Default value') AS attribute
FROM left_table t1
LEFT JOIN right_table t2 ON t1.matching_column = t2.matching_column
WHERE t2.unique_column IS NULL OR t2.unique_column = (/* ваша "золотая" колонка */);
Функция COALESCE
предотвращает появление проблем при наличии пустых значений в правой таблице, при этом поддерживая целостность итогового набора данных.
Полезные материалы
- SQL Joins | Intermediate SQL – Mode — Подробное руководство по работе с
Left Join
. - SQL LEFT JOIN Keyword – W3Schools — Осваивайте
LEFT JOIN
с помощью интерактивных примеров. - LEFT JOIN vs LEFT OUTER JOIN – Difference and Comparison | Diffen — Помощь в понимании разницы между LEFT JOIN и LEFT OUTER JOIN.