Сравнение таблицы SQL с самой собой (самосоединение)

StackOverflow https://stackoverflow.com/questions/1890411

  •  19-09-2019
  •  | 
  •  

Вопрос

Я пытаюсь найти повторяющиеся строки на основе смешанных столбцов.Это пример того, что у меня есть:

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];
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top