2016-05-25 8 views
0

SQL Serverに注文が任意に格納されている異なるテーブルの2つ以上の値を比較するには、迅速な方法が必要です。データは変更されない第三者からのものです。2つ以上の列の値を任意の順序で比較する

以下の例のデータは、2つの方法で説明した同じ項目を示しています。残りの列には、私が参加している他のデータが含まれています。 2のための今

table1 
i j other columns... 
1 2 ... 


table2 
i j other columns 
2 1 ... 
1 2 ... 

、私は両方の方向(I = I、J = J/I = J、J = i)をカバーするためにユニオンクエリを実行します。しかし、あなたが3に拡張するならば、それは9つの可能な注文です。

SELECT * FROM Table1 INNER JOIN Table2 ON Table1.i = Table2.i AND Table1.j = Table2.j 

UNION 

SELECT * FROM Table1 INNER JOIN Table2 ON Table1.i = Table2.j AND Table1.j = Table2.i 

私はすべての労働組合を作成する必要はありませんので、比較を行う前に、最初の2つの列から返されたデータを注文する方法はありますか?

+1

これはどんな意味がありません掲示したよう。あなたにはおそらくかなり明確ですが、私たちが持っているものはすべて、何かについての非常に曖昧な記述です。あなたはあなたの問題についていくつかの実際の詳細を提供できますか? –

+0

私はあなたの質問を理解しているか分からない。期待される結果は何ですか?そして、サンプルデータを追加して期待される結果は何でしょうか? – sgeddes

+0

テーブル1のすべての列とテーブル2のすべての列を比較しようとしているようです。これをプログラムで実行するには、INFORMATION_SCHEMAにアクセスし、それに基づいてSQL文を動的に構築します。比較する前に実際に列の順序を変更することはできませんが、必要はありません。この場合、カラム名が無意味でない限り、カラムの物理的な順序は無意味ですが、それははるかに大きな問題を示しています。 –

答えて

0

編集:新しいXMLアプローチ

私はこのアプローチがどのように実行するか疑問に思う:非常にうまくスケールする必要があり

select *, cast( '<c>' + cast(i as varchar) + '</c>' + 
        '<c>' + cast(j as varchar) + '</c>' + 
        '<c>' + cast(k as varchar) + '</c>' 
      as xml).query('for $a in /c order by $a return concat($a, "/")').value('.', 'varchar(100)') 
from @Table1 o 

これは、関数で包み、永続列で参照することができます...

create table dbo.Table1 (pk int identity(1,1) primary key, i int, j int, k int); 
insert into dbo.Table1 
    values(1, 2, 3), (3, 1, 2), (4, 5, 6), (9,9,9); 
go 

create function dbo.fn_GenerateCompare(@i int, @j int, @k int) 
returns varchar(100) 
with schemabinding 
as 
begin 
return 
(
    select cast('<c>' + cast(@i as varchar) + '</c>' + 
       '<c>' + cast(@j as varchar) + '</c>' + 
       '<c>' + cast(@k as varchar) + '</c>' 
    as xml).query('for $a in /c order by $a return concat($a, "/")').value('.', 'varchar(100)') 
); 
end 

alter table dbo.Table1 
    add Compare as dbo.fn_GenerateCompare(i, j, k) persisted; 


select * from dbo.Table1 

戻り値:

あなたのために
pk i j k Compare 
-- - - - ------- 
1 1 2 3 1/2/3 
2 3 1 2 1/2/3 
3 4 5 6 4/5/6 
4 9 9 9 9/9/9 

あなたの質問は本当に簡単になるはずです。新しいCompare列のインデックスを叩くと飛ぶはずです。




オリジナルポスト:

私はソートされたリストにはThorstenによって提案されたアイデアが好き。それがどのように行われるかもしれないかについての大まかな考えがある。パフォーマンスが大幅にテーブルの上にこのcompare列を永続化することにより改善(トリガまたは計算列を永続化?)されるだろう

declare @Table1 table (pk int identity(1,1) primary key, i int, j int, k int) 
declare @Table2 table (pk int identity(1,1) primary key, i int, j int, k int) 

insert into @Table1 
values(1, 2, 3), (3, 1, 2), (4, 5, 6), (9,9,9) 


insert into @Table2 
values (2, 1, 3), (6, 4, 5) 


--since the order is unimportant, concatenate the columns into a sorted array 
--note how 1,2,3 and 3,1,2 both result in the same compare value: 
select * 
from @Table1 o 
cross 
apply ( select cast(value as varchar) + '/' 
      from @Table1 
      unpivot (value for c in (i,j,k)) as u 
      where pk = o.pk 
      order 
      by  value 
      for xml path('') 
     )d(compare) 

--now, bring in the 2nd table 
select [src] = 1, pk, compare 
from @Table1 o 
cross 
apply ( select cast(value as varchar) + '/' 
      from @Table1 
      unpivot (value for c in (i,j,k)) as u 
      where pk = o.pk 
      order 
      by  value 
      for xml path('') 
     )d(compare) 
union all 
select [src] = 2, pk, compare 
from @Table2 o 
cross 
apply ( select cast(value as varchar) + '/' 
      from @Table2 
      unpivot (value for c in (i,j,k)) as u 
      where pk = o.pk 
      order 
      by  value 
      for xml path('') 
     )d(compare) 


--now just group them to find the matching rows 
select min(src), min(pk), compare 
from ( 
      select [src] = 1, pk, compare 
      from @Table1 o 
      cross 
      apply ( select cast(value as varchar) + '/' 
         from @Table1 
         unpivot (value for c in (i,j,k)) as u 
         where pk = o.pk 
         order 
         by  value 
         for xml path('') 
        )d(compare) 
      union all 
      select [src] = 2, pk, compare 
      from @Table2 o 
      cross 
      apply ( select cast(value as varchar) + '/' 
         from @Table2 
         unpivot (value for c in (i,j,k)) as u 
         where pk = o.pk 
         order 
         by  value 
         for xml path('') 
        )d(compare) 
     )grouped 
group 
by  compare 
having count(*) > 1; 
+0

最初に表示されたピボットレスクエリを使用して、最初と2番目のテーブルと結合するのはなぜですか? – blindguy

+0

何が起こっているのかを説明するのを冗長にするだけです。それらを1つのクエリに分解することができます。 –

+0

gotchaありがとう。それは私のために働いたものです。 – blindguy

関連する問題