1

「結合」テーブルで一致するすべてのオブジェクトを見つけるための効率的なクエリを見つけようとしています。

Adopter多くのオブジェクトがあり、結合テーブルを介して多くのオブジェクトがあるPetsとします。同じものをすべて見つけるにはどうすればよいですか?PetsAdoptersAdopterPetsAdoptersPets

スキーマはかなり正規化されており、次のようになります。

TABLE Adopter
  INTEGER id

TABLE AdopterPets
  INTEGER adopter_id
  INTEGER pet_id

TABLE Pets
  INTEGER id

現在、私が使用しているソリューションはすべてをループしAdopters、一致するペットを保管して後で使用できるようになったらいつでもペットを要求しますが、SQL を使用するより良い方法が必要であると確信しています。

私が調べた 1 つの SQL ソリューションはGROUP BY、この問題に対する適切なトリックではないようでした。

編集

私が探しているものをもう少し説明するために、例を挙げてみます。

+---------+ +------------------+ +------+
| Adptors | | AdptorsPets      | | Pets |
|---------| +----------+-------+ |------|
| 1       | |adptor_id | pet_id| | 1    |
| 2       | +------------------+ | 2    |
| 3       | |1         | 1     | | 3    |
+---------+ |2         | 1     | +------+
            |1         | 2     |
            |3         | 1     |
            |3         | 2     |
            |2         | 3     |
            +------------------+

あなたが同じものを持っている他のものをのAdopterと一緒に尋ねたとき、あなたは返されます.id1AdoptersPetsid 3

の に同じ質問をするAdopterと、id3得られid 1ます。

id 2`の同じ質問をもう一度尋ねた場合、Adopter with 何も返されません。

これが問題を解決するのに役立つことを願っています!

4

4 に答える 4

1

これがまさにあなたが探しているものかどうかはわかりませんが、これはあなたにいくつかのアイデアを与えるかもしれません.

まず、いくつかのサンプル データを作成しました。

create table adopter (id serial not null primary key, name varchar );
insert into adopter (name) values ('Bob'), ('Sally'), ('John');

create table pets (id serial not null primary key, kind varchar);
insert into pets (kind) values ('Dog'), ('Cat'), ('Rabbit'), ('Snake');

create table adopterpets (adopter_id integer, pet_id integer);
insert into adopterpets values (1, 1), (1, 2), (2, 1), (2,3), (2,4), (3, 1), (3,3);

次に、次のクエリを実行しました。

SELECT p.kind, array_agg(a.name) AS adopters
FROM pets p
JOIN adopterpets ap ON ap.pet_id = p.id
JOIN adopter a ON a.id = ap.adopter_id
GROUP BY p.kind
HAVING count(*) > 1
ORDER BY kind;

  kind  |     adopters     
--------+------------------
 Dog    | {Bob,Sally,John}
 Rabbit | {Sally,John}
(2 rows)

この例では、ペットごとにすべての所有者の配列を作成しています。このHAVING count(*) > 1節により、所有者が共有されている (複数の) ペットのみが表示されるようになります。これを省略すると、所有者が同じでないペットが含まれます。

アップデート

@scommette: うまくいってよかった! 以下の作業例を少しリファクタリングしました。

  • @>演算子を使用します。これにより、一方の配列に他方の配列が含まれているかどうかがチェックされ、順序を明示的に設定する必要がなくなります
  • grouped_pets サブクエリを CTE に移動しました。これは単なる解決策ではありませんが、current_adopter_id を除外し、その ID のペットを取得することができます。

これを関数でラップすると役立つ場合があります。

WITH grouped_pets AS (
  SELECT adopter_id, array_agg(pet_id ORDER BY pet_id) AS pets
  FROM adopters_pets
  GROUP BY adopter_id
)
SELECT * FROM grouped_pets
WHERE adopter_id <> 3
  AND pets @> (
    SELECT pets FROM grouped_pets WHERE adopter_id = 3
  );
于 2013-04-15T04:38:48.943 に答える
1

助けてくれてありがとう、私はいくつかのものを組み合わせて使用​​しました:

  SELECT adopter_id
  FROM (
    SELECT adopter_id, array_agg(pet_id ORDER BY pet_id)
    AS pets
    FROM adopters_pets
    GROUP BY adopter_id
  ) AS grouped_pets
  WHERE pets = array[1,2,3]  #array must be ordered
  AND adopter_id <> current_adopter_id;

サブクエリでは、Adopter ごとにグループ化された pet_ids を取得します。メインクエリの結果が順序に依存しないように、pet_ids の順序が重要です。

メイン クエリでは、サブクエリの結果を、照合しようとしているアダプターのペット ID と比較します。この回答の目的のために、特定のアダプターの pet_ids は [1,2,3] で表されます。次に、比較対象の採用者が結果に含まれていないことを確認します。

誰かが最適化を見た場合、または順序が問題にならない配列を比較する方法がある場合はお知らせください。

于 2013-04-15T16:08:37.633 に答える
0

Oracleを使用している場合は、wm_concatここで役立つ可能性があります

select pet_id, wm_concat(adopter_id) adopters
from AdopterPets
group by pet_id ;
于 2013-04-15T04:32:13.820 に答える
0
--
-- Relational division 1.0
-- Show all people who own *exactly* the same (non-empty) set
-- of animals as I do.
--

        -- Test data
CREATE TABLE adopter (id INTEGER NOT NULL primary key, fname varchar );
INSERT INTO adopter (id,fname) VALUES (1,'Bob'), (2,'Alice'), (3,'Chris');

CREATE TABLE pets (id INTEGER NOT NULL primary key, kind varchar);
INSERT INTO pets (id,kind) VALUES (1,'Dog'), (2,'Cat'), (3,'Pig');

CREATE TABLE adopterpets (adopter_id integer REFERENCES adopter(id)
        , pet_id integer REFERENCES pets(id)
        );
INSERT INTO adopterpets (adopter_id,pet_id) VALUES (1, 1), (1, 2), (2, 1), (2,3), (3,1), (3,2);

        -- Show it to the world
SELECT ap.adopter_id, ap.pet_id
        , a.fname, p.kind
FROM adopterpets ap
JOIN adopter a ON a.id = ap.adopter_id
JOIN pets p ON p.id = ap.pet_id
ORDER BY ap.adopter_id,ap.pet_id;
SELECT DISTINCT other.fname AS same_as_me
FROM adopter other
        -- moi has *at least* one same kind of animal as toi
WHERE EXISTS (
        SELECT * FROM adopterpets moi
        JOIN adopterpets toi ON moi.pet_id = toi.pet_id
        WHERE toi.adopter_id = other.id
        AND moi.adopter_id <> toi.adopter_id
                -- C'est moi!
        AND moi.adopter_id = 1 -- 'Bob'
        -- But moi should not own an animal that toi doesn't have
        AND NOT EXISTS (
                SELECT * FROM adopterpets lnx
                WHERE lnx.adopter_id = moi.adopter_id
                AND NOT EXISTS (
                        SELECT *
                        FROM adopterpets lnx2
                        WHERE lnx2.adopter_id = toi.adopter_id
                        AND lnx2.pet_id = lnx.pet_id
                        )
                )
        -- ... And toi should not own an animal that moi doesn't have
        AND NOT EXISTS (
                SELECT * FROM adopterpets rnx
                WHERE rnx.adopter_id = toi.adopter_id
                AND NOT EXISTS (
                        SELECT *
                        FROM adopterpets rnx2
                        WHERE rnx2.adopter_id = moi.adopter_id
                        AND rnx2.pet_id = rnx.pet_id
                        )
                )
        )
        ;

結果:

NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "adopter_pkey" for table "adopter"
CREATE TABLE
INSERT 0 3
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "pets_pkey" for table "pets"
CREATE TABLE
INSERT 0 3
CREATE TABLE
INSERT 0 6
 adopter_id | pet_id | fname | kind 
------------+--------+-------+------
          1 |      1 | Bob   | Dog
          1 |      2 | Bob   | Cat
          2 |      1 | Alice | Dog
          2 |      3 | Alice | Pig
          3 |      1 | Chris | Dog
          3 |      2 | Chris | Cat
(6 rows)

 same_as_me 
------------
 Chris
(1 row)
于 2013-04-16T11:00:49.120 に答える