4

INNER JOINを実行したい2つの単純なテーブルがありますが、問題は、(列str1とstr2の)結果が重複していることです。

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  

本当に2つ欲しかったのに4つのレコードができました。

私が得たもの:
id | 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のみを使用したいと思います。

4

3 に答える 3

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 ;

同じ組み合わせの1つまたは他のテーブルにさらに行がある場合は、joinを、またはjoinに(str1, str2)変更して、返される行を選択できます。INNERLEFTRIGHTFULL

于 2012-11-23T20:00:26.520 に答える
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のセットごとにアイテムの数が等しくない場合、#Aまたは#BにNULLが表示されるため、予期しない結果が生じる可能性があります。

ここでは、#A.Id(1が最初)の順序でテーブル#Aの「Str1Str2」の最初の行を、順序どおりにテーブル#Bの「Str1Str2」の最初の行と相関させる必要があると想定しています。 #B.Id(7が最初)などによって、連続して番号が付けられた行ごとに続きます。そうですか?

しかし、行数が一致せず、たとえば、#Bの2行と同じ値を持つ#Aの3行がある場合は、どうしますか?またはその逆?あなたは何が見たいですか?

データが複製されないため、単なるDISTINCTでは機能しません。部分的な相互結合(部分的なデカルト積になります)が実際に行われているものを取得しています。つまり、結合基準は、#A行と#B行が1対1で対応していることを保証するものではありません。その場合、 #Aの各行について、Bの一致する行ごとに出力行が取得されます。2x2 = 4、2ではありません。

あなたがあなたの例でもう少し具体的になれば、それは助けになると思います。実際に何を照会していますか?確かにあなたは私たちのために単純化しましたが、それはまたあなたが現実の世界で何を達成しようとしているのかを知るために私たちのすべての文脈を取り除きました。スポーツチームを並べようとしている場合は、請求書の広告申込情報や遅れた出来事を並べようとしている場合、または誰が何を知っているかとは異なる答えを出す可能性があります。

于 2012-11-23T19:55:15.110 に答える
1

そのデータとそのデータだけでは、#Aの各ID値を各#BのID値にマップする方法を提供できない限り、希望する結果を得ることができません。

したがって、各テーブルに実際に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から一致するレコードの可能なすべての組み合わせを取得します。

使用する必要がある他のフィールドはIDフィールドのみであるため、これらを使用して、1つのAレコードと1つのBレコードを正確に組み合わせる必要があります。

于 2012-11-23T19:52:00.143 に答える