2

次のような2つのテーブルがあります。

create table doi (
    id number primary key not null,
    -- Other columns omitted
);

create table doi_membership (
    id number primary key not null,
    doi_id number not null, --foreign key to doi.id
    key_1 number not null,
    key_2 number not null,
    -- Other columns omitted
);

key_1 と key_2 のペアのセットがあり、指定された key_1 と key_2 のペアの完全なセットを含む doi があるかどうかを確認したいと考えています。これを行うために必要な SQL が思い浮かびません。それが役立つ場合、私はOracleデータベースを使用しています。何か案は?

アップデート:

うまく説明できなかったと思うので、例を挙げて説明します。

概念的には、1 つの DOI に key_1 と key_2 のペアのリストが含まれます。key_1 と key_2 のペアの独自のリストがあり、ペアのリストがペアのリストと完全に一致する DOI が存在するかどうかを確認したいと考えています。

したがって、次のような key_1 と key_2 のペアのリストを持つ DOI があるとします (これらの各行は、同じ doi に関連する個別の doi_membership 行です)。

1, 2
3, 4
5, 6

そして、次のペアのリストを持つ別の DOI:

1, 2
3, 4
5, 6
7, 8

私が持っているペアのセットは

1, 2
3, 4
5, 6

ペアのセットと私のペアのセットが完全に一致するため、指定された最初の DOI を一致させたいと考えています。2 番目の DOI は一致しません。

これで問題が解決することを願っています。

4

4 に答える 4

1

HAVINGセット メンバーシップにアプローチする最善の方法は、SQL で句を使用することだと思います。アイデアは、セットの要素 (この場合は各 doi のメンバーシップ レコード) をグループ化し、個々のレベルでテストを行うことです。

たとえば、次の having 句は、keyval1 が存在することを確認します。

having sum(case when keyval_1 = <keyval1> then 1 else 0 end) > 0

これは、レコード数を で合計することによって行われkeyval_1 = <keval1>ます。0以上あれば「doi_id」が条件を満たす。

値のペアを見ているため、条件は少し複雑です。これを解決する 1 つの方法は、値を連結することです (必須ではありませんが、ロジックがいくらか単純化されます)。次の句は、値のペアのみが doi_id に存在することを確認します。

having sum(case when concat(key_1, ',', key_2) in (<key value pairs here>)
                then 0 else 1 end) = 0

キーペアが一致しないレコードの数を数えます。存在する場合、比較は失敗します。in 句のキーと値のペアを連結する必要があります。のようなものin ('1,1', '2,2', '3,14')

すべてが一致するという条件に一般化するには、次を使用します。

select doi_id
from doi_membership
group by doi_id
having sum(case when concat(key_1, ',', key_2) in (<key value pairs here>)
                then 0 else 1 end) = 0 and 
       sum(case when concat(key_1, ',', key_2) = <key pair 1>
                then 1 else 0 end) > 0 and
       sum(case when concat(key_1, ',', key_2) = <key pair 2>
                then 1 else 0 end) > 0 and
       . . .
       sum(case when concat(key_1, ',', key_2) = <key pair n>
                then 1 else 0 end)

このHAVING句は、最初にすべてのペアが存在することをテストします。次に、残りの句で各ペアの存在をテストします。

他のアプローチもあります。HAVINGこの句は、セットの包含基準に関する幅広いロジックに対応できるため、最も一般的であることがわかりました。

于 2012-10-04T18:18:53.337 に答える
1

キーペアのリストがテーブルに保存されていると仮定すると、次の別のアプローチを検討できます。

SELECT m.doi_id
FROM doi_membership m
LEFT JOIN sample_key_set s
  ON m.key_1 = s.key_1 AND m.key_2 = s.key_2
GROUP BY m.doi_id
HAVING COUNT(*) = ALL(
  COUNT(s.key_1),
  (SELECT COUNT(*) FROM sample_key_set)
)
;

doi_membershipクエリは、ペアのサンプル リストに外部結合し、結果セットdoi_idをグループ化し、グループ内の行の合計数を、一致する行の合計数およびサンプル ペアの合計数と比較します。すべてのカウントが等しい場合、対応する値doi_idが返されます。

ALL 述語を認識していない場合、この条件は

COUNT(*) = ALL(
  COUNT(s.key_1),
  (SELECT COUNT(*) FROM sample_key_set)
)

は単なるショートカットです

    COUNT(*) = COUNT(s.key_1)
AND COUNT(*) = (SELECT COUNT(*) FROM sample_key_set)

メソッドが機能することを示すために、分析されたさまざまな例を次に示します。

#   Rows in "m"  Rows in "s"  Count values          Outcome
--  -----------  -----------  --------------------  -------
1      1, 2         1, 2      COUNT(*)          =2  MATCH
       3, 4         3, 4      COUNT(s.key_1)    =2
                              SELECT COUNT(*)...=2
--  -----------  -----------  --------------------  -------
2      1, 2         1, 2      COUNT(*)          =1  NO
                    3, 4      COUNT(s.key_1)    =1  MATCH
                              SELECT COUNT(*)...=2
--  -----------  -----------  --------------------  -------
3      1, 2         1, 2      COUNT(*)          =2  NO
       5, 6         3, 4      COUNT(s.key_1)    =1  MATCH
                              SELECT COUNT(*)...=2
--  -----------  -----------  --------------------  -------
4      1, 2         1, 2      COUNT(*)          =3  NO
       3, 4         3, 4      COUNT(s.key_1)    =2  MATCH
       5, 6                   SELECT COUNT(*)...=2

ご覧のとおり、このメソッドでは、キー セットが完全に一致する DOI のみが返されます。

サンプルのキー ペア リストをテーブルに格納する代わりに、次のような一般的なテーブル式を使用できます。

WITH sample_key_set AS (
  SELECT key1, key2 FROM DUAL UNION ALL
  SELECT key3, key4 FROM DUAL UNION ALL
  ...
)
SELECT m.doi_id
FROM ... /* the rest of the above query */

また、SQL Fiddle でメソッドのデモンストレーションを行って遊ぶこともできます。

于 2012-10-04T22:21:35.347 に答える
0
SELECT <whatever you need>
FROM doi_membership
WHERE (Key_1 = <key value your looking for> AND Key_2 = <key value you're looking for>)

私が質問を読み違えていない限り、それは簡単だと思います

于 2012-10-04T18:06:12.740 に答える
0

自己結合を使用することはできませんか?

パラメータ/ハードコードされたキーペアの値に対してのみ、内部比較は必要ありません。

内部チェックは次のようになります。

SELECT 
    d.doi_ID, 
    c.CountOfID
FROM 
    doiMembership d INNER JOIN 
    (SELECT 
    doi_ID,Count(ID) CountOfID
    FROM doiMembership
    GROUP BY doi_ID) c ON 
    d.doi_ID = c.doi_ID INNER JOIN 
    (SELECT 
    doi_ID, Count(ID) CountOfID
    FROM doiMembership
    GROUP BY doi_ID) c2  on
    c2.CountOfID = c.CountOfID  inner join
    doiMembership d2 ON 
    c2.doi_ID = d2.doi_ID and
    c.CountOfID = d2.CountOfID AND 
    (d.key1 = d2.[key1]) AND 
    (d.key2 = d2.[key2])
WHERE 
    (d.ID <> d2.[id]) 
GROUP BY 
    d.doi_ID, 
    c.CountOfID

ただし、既知の doi と比較したい場合は、次を使用できます。

SELECT 
    d.doi_ID, 
    c.CountOfID
FROM 
    doiMembership d INNER JOIN 
    (SELECT 
    doi_ID,Count(ID) AS CountOfID
    FROM doiMembership
    GROUP BY doi_ID) c ON 
    d.doi_ID = c.doi_ID INNER JOIN 
    (SELECT 
    doi_ID, Count(ID) AS CountOfID
    FROM doiMembership
    GROUP BY doi_ID) c2  INNER JOIN 
    doiMembership AS d2 ON 
    c2.doi_ID = d2.doi_ID and
    c.CountOfID = d2.CountOfID
WHERE 
    (d.ID <> d2.[id]) AND 
    (d.key1 = d2.[key1]) AND 
    (d.key2 = d2.[key2]) and
    d.doi_id = 'value'
GROUP BY 
    d.doi_ID, 
    c.CountOfID
于 2012-10-04T19:19:25.657 に答える