Сравнение таблицы SQL с самой собой (самосоединение)
Вопрос
Я пытаюсь найти повторяющиеся строки на основе смешанных столбцов.Это пример того, что у меня есть:
CREATE TABLE Test
(
id INT PRIMARY KEY,
test1 varchar(124),
test2 varchar(124)
)
INSERT INTO TEST ( id, test1, test2 ) VALUES ( 1, 'A', 'B' )
INSERT INTO TEST ( id, test1, test2 ) VALUES ( 2, 'B', 'C' )
Теперь, если я запущу этот запрос:
SELECT [LEFT].[ID]
FROM [TEST] AS [LEFT]
INNER JOIN [TEST] AS [RIGHT]
ON [LEFT].[ID] != [RIGHT].[ID]
WHERE [LEFT].[TEST1] = [RIGHT].[TEST2]
Я ожидал бы вернуть оба идентификатора.(1 и 2), однако я возвращаю только одну строку.
Я думаю, что следует сравнивать каждую строку, но я думаю, это неправильно?Чтобы исправить это, я изменил свой запрос на:
SELECT [LEFT].[ID]
FROM [TEST] AS [LEFT]
INNER JOIN [TEST] AS [RIGHT]
ON [LEFT].[ID] != [RIGHT].[ID]
WHERE [LEFT].[TEST1] = [RIGHT].[TEST2]
OR [LEFT].[TEST2] = [RIGHT].[TEST1]
Это дает мне обе строки, но производительность очень быстро снижается в зависимости от количества строк.
Окончательное решение, которое я придумал для повышения производительности и результатов, заключалось в использовании объединения:
SELECT [LEFT].[ID]
FROM [TEST] AS [LEFT]
INNER JOIN [TEST] AS [RIGHT]
ON [LEFT].[ID] != [RIGHT].[ID]
WHERE [LEFT].[TEST1] = [RIGHT].[TEST2]
UNION
SELECT [LEFT].[ID]
FROM [TEST] AS [LEFT]
INNER JOIN [TEST] AS [RIGHT]
ON [LEFT].[ID] != [RIGHT].[ID]
WHERE [LEFT].[TEST2] = [RIGHT].[TEST1]
Но в целом мне явно не хватает понимания, почему это не работает, а это значит, что я, вероятно, делаю что-то не так.Может ли кто-нибудь указать мне правильное направление?
Решение
Не ПРИСОЕДИНЯЙТЕСЬ к неравенству;кажется, что условия JOIN и WHERE инвертированы.
SELECT t1.id
FROM Test t1
INNER JOIN Test t2
ON ((t1.test1 = t2.test2) OR (t1.test2 = t2.test1))
WHERE t1.id <> t2.id
Должно работать нормально.
Другие советы
Вы получите оба идентификатора только в том случае, если вы их выберете:
SELECT [LEFT].[ID], [RIGHT].[ID]
FROM [TEST] AS [LEFT]
INNER JOIN [TEST] AS [RIGHT]
ON [LEFT].[ID] != [RIGHT].[ID]
WHERE [LEFT].[TEST1] = [RIGHT].[TEST2]
Причина, по которой получается только одна строка, заключается в том, что только одна строка (а именно строка № 2) имеет TEST1, равный TEST2 другой строки.
Мне кажется, ты очень быстро работаешь над Картезианское соединение.Обычно, если вы хотите вернуть дубликаты, вам нужно запустить что-то вроде:
SELECT [LEFT].*
FROM [TEST] AS [LEFT]
INNER JOIN [TEST] AS [RIGHT]
ON [LEFT].[test1] = [RIGHT].[test1]
AND [LEFT].[test2] = [RIGHT].[test2]
AND [LEFT].[id] <> [RIGHT].[id]
Если вам нужно смешать столбцы, то смешайте нужные условия, но сделайте что-то вроде:
SELECT [LEFT].*
FROM [TEST] AS [LEFT]
INNER JOIN [TEST] AS [RIGHT]
ON (
[LEFT].[test1] = [RIGHT].[test2]
OR [LEFT].[test2] = [RIGHT].[test1]
)
AND [LEFT].[id] <> [RIGHT].[id]
Используя это, вы сравниваете правое и левое и левое правое в каждом соединении, полностью устраняя необходимость в WHERE.
Однако время выполнения этого типа запроса растет экспоненциально для каждой строки, вставленной в таблицу, поскольку вы сравниваете каждую строку с каждой строкой.
Если я не ошибаюсь, это можно сделать без внутренних соединений.Я впервые отвечаю на вопрос типа MySQL, но я отвечаю просто для того, чтобы получить больше очков здесь, на StackOverflow.Запятая очень важна, чтобы MySQL не жаловался.
SELECT [LEFT].[ID] FROM [TEST] AS [LEFT], [TEST] AS [RIGHT]
WHERE [LEFT].[ID] != [RIGHT].[ID]
AND [LEFT].[TEST1] = [RIGHT].[TEST2];