1

X と Y の 2 つのテーブルがあり、スキーマは同じですが、レコードは異なります。X からのレコードが与えられた場合、一致しない列の NULL 値を含む Y で最も一致するレコードを見つけるためのクエリが必要です。ID 列は比較から除外する必要があります。たとえば、私のレコードが次のようになっているとします。

------------------------
id | col1 | col2 | col3
------------------------
0  |'abc' |'def' | 'ghi'

テーブル Y は次のようになります。

------------------------
id | col1 | col2 | col3
------------------------
6  |'abc' |'def' | 'zzz'
8  | NULL |'def' | NULL

列が一致しない場所には NULL 値があるため、最も近い一致はレコード 8 になります。6 が最も近い試合だったはずですが、「zzz」が失格となりました。

この問題のユニークな点は、id 列とデータ型以外にテーブルのスキーマが不明であることです。4 つの列がある場合もあれば、7 つの列がある場合もあります。わからないだけです-それは動的です。わかっているのは、「id」列があり、その列が varchar または nvarchar のいずれかの文字列になることだけです。

この場合、X からのレコードが与えられた場合に、Y から最も近い一致するレコードを選択するための最適なクエリは何ですか? 私は実際に関数を書いています。入力は整数 (X のレコードの ID) で、出力は整数 (Y のレコードの ID、または NULL) です。私は SQL の初心者なので、ソリューションで何が起こっているかを簡単に説明していただけると非常に助かります。

4

1 に答える 1

3

4 列かもしれませんし、7 列かもしれません.... 私は実際に関数を書いています。

これは不可能な作業です。関数は決定論的であるため、動的 SQL を使用して、任意のテーブル構造で機能する関数を作成することはできません。確かにストアド プロシージャですが、関数ではありません。

ただし、以下は、FOR XML を使用し、XML をいくつか分解して、行を列名と値にピボット解除し、比較できるようにする方法を示しています。ここで使用される手法とクエリは、ストアド プロシージャに組み込むことができます。

MS SQL Server 2008 スキーマのセットアップ:

-- this is the data table to match against
create table t1 (
    id int,
    col1 varchar(10),
    col2 varchar(20),
    col3 nvarchar(40));
insert t1
select 6, 'abc', 'def', 'zzz' union all
select 8, null , 'def', null;

-- this is the data with the row you want to match
create table t2 (
    id int,
    col1 varchar(10),
    col2 varchar(20),
    col3 nvarchar(40));
insert t2
select 0, 'abc', 'def', 'ghi';
GO

クエリ 1 :

;with unpivoted1 as (
    select n.n.value('local-name(.)','nvarchar(max)') colname,
           n.n.value('.','nvarchar(max)') value
    from (select (select * from t2 where id=0 for xml path(''), type)) x(xml)
    cross apply x.xml.nodes('//*[local-name()!="id"]') n(n)
), unpivoted2 as (
    select x.id,
           n.n.value('local-name(.)','nvarchar(max)') colname,
           n.n.value('.','nvarchar(max)') value
    from (select id,(select * from t1 where id=outr.id for xml path(''), type) from t1 outr) x(id,xml)
    cross apply x.xml.nodes('//*[local-name()!="id"]') n(n)
)
select TOP(1) WITH TIES
       B.id,
       sum(case when A.value=B.value then 1 else 0 end) matches
from unpivoted1 A
join unpivoted2 B on A.colname = B.colname
group by B.id
having max(case when A.value <> B.value then 1 end) is null
ORDER BY matches;

結果

| ID | MATCHES |
----------------
|  8 |       1 |
于 2012-11-13T21:42:34.947 に答える