3

У меня есть 2 простых таблиц, которые я хотел бы выполнить внутреннее соединение с, но проблема в том, что я получаю дублированы (для str1 колонн и str2) результаты:Дублированные результаты при выполнении INNER JOIN

CREATE TABLE #A (Id INT, str1 nvarchar(50), str2 nvarchar(50)) 
insert into #A values (1, 'a', 'b') 
insert into #A values (2, 'a', 'b') 

CREATE TABLE #B (Id INT, str1 nvarchar(50), str2 nvarchar(50)) 
insert into #B values (7, 'a', 'b') 
insert into #B values (8, 'a', 'b') 

select * from #A a 
INNER JOIN #B b ON a.str1 = b.str1 AND a.str2 = b.str2 

Он дал мне 4 записи, когда я действительно хотел 2.

Что я получил:
идентификатор | str1 | str2 | id | str1 | str2
1 | a | b | 7 | a | b
2 | a | b | 7 | a | b
1 | a | b | 8 | a | b
2 | a | b | 8 | a | b

Что я действительно хотел:
1 a | b | 7 | a | b
2 a | b | 8 | a | b

Может ли кто-нибудь помочь? Я знаю, что это возможно с помощью курсора и цикла, но я бы хотел его избежать и использовать только какой-либо тип JOIN, если это возможно.

ответ

5
SELECT 
    a.id AS a_id, a.str1 AS a_str1, a.str2 AS a_str2, 
    b.id AS b_id, b.str1 AS b_str1, b.str2 AS b_str2 
FROM 
    (SELECT * 
      , ROW_NUMBER() OVER (PARTITION BY str1, str2 ORDER BY id) AS rn 
     FROM #A 
    ) a 
    INNER JOIN 
    (SELECT * 
      , ROW_NUMBER() OVER (PARTITION BY str1, str2 ORDER BY id) AS rn 
     FROM #B 
    ) b 
    ON a.str1 = b.str1 
    AND a.str2 = b.str2 
    AND a.rn = b.rn ; 

Если у вас есть несколько строк в одном или другие таблицы для одной и той же (str1, str2) комбинации, вы можете выбрать, какие из них будут возвращены путем изменения INNER присоединиться к любому LEFT, RIGHT или FULL присоединиться.

+0

Спасибо, это отлично работает! – codetc

1

С этими данными и только этими данными вы не можете получить желаемый результат, если только вы не можете предоставить какой-либо способ для каждого из значений идентификатора # A для сопоставления с каждым из значений идентификатора # B.

Так что, если вы на самом деле есть только 2 записей в каждой таблице, она будет идти что-то вроде этого:

SELECT * 
FROM #A a 
    JOIN #B b 
     ON a.str1 = b.str1 -- actually, if you join by IDs this isn't necessary 
     AND a.str2 = b.str2 -- nor is this 
     AND 
     (
      (a.ID = 1 and b.ID = 7) 
     OR (a.ID = 2 and b.ID = 8) 
    ) 

Что вы получаете называется декартово произведение, где каждая запись в #A спарен с каждой соответствующей записью в #B. Поскольку в каждой таблице имеется более одной соответствующей записи, вы получаете все возможные комбинации совпадающих записей от A и B.

Поскольку только другие поля, с которыми вы должны работать, - это поля идентификатора, вы должны использовать их для объединить ровно одну запись A с одной записью B.

3

Вы может выполнить свой род соответствие с запросом, как в следующем (SQL 2005 и выше):

WITH A AS (
    SELECT 
     Seq = Row_Number() OVER (PARTITION BY Str1, Str2 ORDER BY Id), 
     * 
    FROM #A 
), B AS (
    SELECT 
     Seq = Row_Number() OVER (PARTITION BY Str1, Str2 ORDER BY Id), 
     * 
    FROM #B 
) 
SELECT 
    A.Id, A.Str1, A.Str2, B.Id, B.Str1, B.Str2 
FROM 
    A 
    FULL JOIN B 
     ON A.Seq = B.Seq AND A.Str1 = B.Str1 AND A.Str2 = B.Str2; 

Это соединяет элементы между A и B на их Id упорядоченного положения. Но обратите внимание: если у вас есть не равное количество элементов для каждого набора Str1 и Str2, вы можете получить неожиданные результаты, так как NULL появятся для #A или #B.

Я предполагаю, что вы хотите, чтобы первая строка таблицы «A Str1 Str2» таблицы A была упорядочена по # A.Id (сначала 1), чтобы коррелировать с первой строкой таблицы № B «Str1 Str2» », как указано в # B.Id (сначала 7) и т. д. и т. д. для каждой последовательно пронумерованной строки. Это правильно?

Но что вы будете делать, если количество строк не совпадает, и есть, например, 3 строки в #A, которые имеют те же значения, что и 2 строки в #B? Или наоборот? Что бы вы хотели увидеть?

Просто DISTINCT не будет выполнять работу, потому что данные не дублируются. Вы получаете то, что в действительности является частичным перекрестным соединением (в результате получается частичное декартово произведение). То есть, ваши критерии присоединения не гарантируют, что существует взаимно однозначное соответствие строки #A для строки #B. Когда это произойдет, для каждая строка в #A вы получите строку вывода для каждый подходящая строка в B. 2 x 2 = 4, а не 2.

Я думаю, это помогло бы, если бы вы были немного более конкретными в своем примере. Что вы на самом деле запрашиваете? Конечно, вы упростили для нас, но это также устранило весь контекст для нас, чтобы узнать, чего вы пытаетесь достичь в реальном мире. Если вы пытаетесь выстроиться в спортивные команды, мы могли бы дать другой ответ, чем если бы вы пытались выстроить позиции счета или опоздать или кто знает что!

+0

Спасибо ErikE, это также сработало, как ожидалось, если у меня есть равное количество записей в каждой таблице. Мой сценарий очень сложный, поэтому я упростил его. В основном моя цель - получить результат индивидуального сопоставления, который мне нужно будет использовать для дальнейших вычислений. – codetc