5

私はこのテーブルを持っています

 ----------------
|   X    |   Y   |
 ----------------
|   a    |   1   |
|   c    |   6   |
|   e    |   3   |
|   d    |   6   |
|   c    |   4   |
|   b    |   1   |
|   a    |   5   |
|   g    |   1   |
 ----------------

配列 [c,d] が与えられた場合、上の表で「6」を見つける必要があります。つまり、要素のすべてのセットについて、セット内のすべての要素によって共有される Y 値を見つける必要がありますが、その値を共有する他の要素 (つまり、指定された配列にない要素) がない場合に限ります。配列の要素数に理論上の制限はありません。

その他の例: [a,b,c] の場合、何も検索する必要はありません。[a,b] についても、何も検索する必要はありません (g には Y = 1 のエントリもあるため、[a,b,g] については "1" を検索する必要があります)。

もちろん、クエリごとに配列を反復処理することもできますが、それは非常に非効率的な方法のようです。SQLでこれを行う最良の方法は何ですか? ありがとうございました。

4

2 に答える 2

2

これらのタイプのクエリは、大規模なデータセットや、Y の多くの値が X の同じ値を共有している場合に特にパフォーマンスが向上することはありません。

とはいえ、これは私の通常の方法の単純なバージョンです...

CREATE TEMPORARY TABLE params (
  item VARCHAR(16)
)
INSERT INTO params SELECT 'a'
INSERT INTO params SELECT 'b'
INSERT INTO params SELECT 'g'


SELECT
  yourTable.Y
FROM
  yourTable
LEFT JOIN
  params
    ON yourTable.X = params.item
GROUP BY
  yourTable.Y
HAVING
  COUNT(DISTINCT yourTable.X) = COUNT(DISTINCT params.item)


パラメータテーブルを必要としない別のオプションですが、パフォーマンスが向上するとは思いません...

SELECT
  y
FROM
  yourTable
GROUP BY
  y
HAVING
  COUNT(DISTINCT x) = COUNT(DISTINCT CASE WHEN x IN ('a', 'b', 'g') THEN x ELSE NULL END)

これには結合はありませんが、全テーブル スキャンを実行するという犠牲が伴います。

于 2012-07-04T16:25:06.660 に答える
2

「クエリ」値を別のテーブルに入れる方法を次に示します。

create table t ( x varchar(1), y int);

insert into t (x, y) values ('a', 1);
insert into t (x, y) values ('c', 6);
insert into t (x, y) values ('e', 3);
insert into t (x, y) values ('d', 6);
insert into t (x, y) values ('c', 4);
insert into t (x, y) values ('b', 1);
insert into t (x, y) values ('a', 5);
insert into t (x, y) values ('g', 1);

create table q ( x varchar(1) );

insert into q (x) values ('a');
insert into q (x) values ('b');

select a.y from
(
   select t.y
     from t join q on (t.x = q.x)
   group by t.y
   having count(*) = (select count(*) from q)
) a 
join t on (a.y = t.y) 
group by a.y
having count(*) = (select count(*) from q)

SQLFiddle の例を次に示します。

これは、組み合わせが重複しないことを前提としています。

2 番目のテーブルなしで実行したい場合はselect count(*)、IN リストで一致する値の数に置き換えることができます。内部サブクエリで結合を行う代わりに、where 句を使用します。

select a.y from
(
select t.y
from t
  where t.x in ('c', 'd')
group by t.y
having count(*) = 2
) a 
join t on (a.y = t.y) 
group by a.y
having count(*) = 2
于 2012-07-04T16:30:46.963 に答える