#sql #sql-server
#sql #sql-сервер
Вопрос:
У меня есть таблица Companies
, которую я хотел бы отфильтровать только для записей, на которые ссылаются две другие таблицы, Employees
и Contracts
.
Мой первоначальный инстинкт заключается в том, что я мог бы сделать что-то вроде этого:
SELECT c.*
FROM Companies c
JOIN Employees ON EmployerId = c.Id
JOIN Contracts ON CompanyId = c.Id
Однако при этом выбираются записи, на которые ссылаются обе Employees
Contracts
таблицы и .
Как мне переписать этот запрос, чтобы сопоставить записи, на которые ссылаются из любой таблицы?
Комментарии:
1. Похоже, вам нужно пересечь
Ответ №1:
Изначально я создал версию с ошибками, которая завершилась неудачей, с ЛЕВЫМИ ВНЕШНИМИ СОЕДИНЕНИЯМИ. Это можно было бы исправить, но на самом деле, вероятно, более эффективно использовать ТАМ, ГДЕ СУЩЕСТВУЕТ, например,
SELECT c.*
FROM Companies c
WHERE EXISTS (SELECT EmployerID FROM Employee WHERE EmployerID = c.ID)
OR EXISTS (SELECT CompanyId FROM Contracts WHERE CompanyId = c.ID)
Причина, по которой моя предыдущая версия была ошибочной, заключалась в том, что в ней было соединение с сотрудниками и контрактами, что означало, что оно возвращало бы одну строку для каждой существующей (и, возможно, перекрестное произведение результатов). Даже с GROUP BY или DISTINCT, вероятно, SQL Server пришлось бы проделать большую работу.
Приведенное выше решение получает только одну строку для каждой компании, независимо от количества сотрудников или контрактов.
Комментарии:
1. Это кажется намного более элегантным, чем обычное решение, которое заключается в ОБЪЕДИНЕНИИ соединений. К тому времени, когда я вызвал DISTINCT для удаления дубликатов, я подозреваю, что это намного медленнее, чем то, что вы предложили.
2. Поскольку результаты этого запроса помещаются во временную таблицу, мой текущий обходной путь — просто добавить второе СОЕДИНЕНИЕ во временную таблицу с помощью INSERT INTO . Это тоже работает, но не так быстро и не имеет дело с дубликатами.
3. Будет ли это работать лучше, если я использую «SELECT 1» вместо «SELECT EmployerId» и «SELECT CompanyID»?
4. ‘SELECT 1’ может дать вам очень незначительный прирост производительности. ‘SELECT * ‘ также может это сделать. Но на практике я не заметил разницы. Попробуйте повернуть
SET STATISTICS TIME, IO ON
и попробовать их (в разных порядках), чтобы увидеть. Что касается наилучших ответов, иногда это зависит от размера данных и индексов. Если у вас много данных, вышеуказанное также может вызвать проблемы. Вы также можете попробоватьSELECT c.* FROM Companies c INNER JOIN (SELECT EmployerID as ID FROM Employees UNION SELECT CompanyID FROM Contracts) a ON c.Id = a.Id
Ответ №2:
Вероятно UNION
, для этого вам понадобится
SELECT c.*
FROM Companies c
JOIN Employees ON EmployerId = c.Id
UNION
SELECT c.*
FROM Companies c
JOIN Contracts ON CompanyId = c.Id