2

私は3つのテーブルを持っています:

CREATE TABLE foo (
    id bigint PRIMARY KEY,
    name text NOT NULL
);

CREATE TABLE foo_bar (
    id bigint PRIMARY KEY,
    foo_id bigint NOT NULL
);

CREATE TABLE tag (
    name text NOT NULL,
    target_id bigint NOT NULL,
    PRIMARY KEY (name, target_id)
);

テーブルのすべてのフィールド、 wherefoo内のアイテムの数、およびwhere内のすべてのタグのテキスト配列を取得するようなビューを作成しようとしています。私たちが持っている場合:foo_barfoo.id = foo_bar.foo_idfoo.id = tag.target_id

INSERT INTO foo VALUES (1, 'one');
INSERT INTO foo VALUES (2, 'two');
INSERT INTO foo_bar VALUES (1, 1);
INSERT INTO foo_bar VALUES (2, 1);
INSERT INTO foo_bar VALUES (3, 2);
INSERT INTO foo_bar VALUES (4, 1);
INSERT INTO foo_bar VALUES (5, 2);
INSERT INTO tag VALUES ('a', 1);
INSERT INTO tag VALUES ('b', 1);
INSERT INTO tag VALUES ('c', 2);

結果は次のようになります。

foo.id    | foo.name     | count       | array_agg
--------------------------------------------------
1         | one          | 3           | {a, b}
2         | two          | 2           | {c}

これは私がこれまでに持っているものです:

SELECT DISTINCT f.id, f.name, COUNT(b.id), array_agg(t.name)
FROM foo AS f, foo_bar AS b, tag AS t
WHERE f.id = t.target_id AND f.id = b.foo_id
GROUP BY f.id, b.id;

これらは私が得ている結果です(count間違っていることに注意してください):

foo.id    | foo.name     | count       | array_agg
--------------------------------------------------
1         | one          | 2           | {a, b}
2         | two          | 1           | {c}

個別の値countの数ではなく、常にタグの数foo_barです。GROUP BYと句を並べ替え/変更してみましたSELECTが、探しているものではなく、異なる結果が返されます。機能に問題があると思いますが、それが問題array_agg()なのか、どうすれば解決できるのかわかりません。

4

1 に答える 1

8
SELECT f.id, f.name, b.fb_ct, t.tag_names
FROM   foo f
LEFT JOIN  (
    SELECT foo_id AS id, count(*) AS fb_ct
    FROM   foo_bar
    GROUP  BY 1
    ) b USING (id)
LEFT JOIN  (
    SELECT target_id AS id, array_agg(name) AS tag_names
    FROM   tag
    GROUP  BY 1
    ) t USING (id)
ORDER  BY f.id;

望ましい結果が得られます。

  • JOIN明示的な構文で書き直します。読みやすく、理解しやすく (そしてデバッグしやすく) なっています。

  • 複数の関連するテーブルに結合することにより1:n、行が互いに乗算され、デカルト積が生成されます。これは非常に高価でナンセンスです。意図しないCROSS JOINプロキシです。関連している:

  • これを回避するには、集約する前に、多くても1 つ nの -table を -table に結合し1ます ( GROUP BY)。2 回集計することもできますが、 -table に結合するnに、 -table を個別に集計する方がクリーンで高速です。1

  • オリジナルとは対照的に(暗黙的INNER JOIN)。またはに一致する行がないLEFT JOIN行を失うことを避けるために使用します。foofoo_bartag

  • クエリから意図しないCROSS JOINものが削除されたら、それ以上追加する必要はありません-それが一意であるとDISTINCT仮定します。foo.id

于 2013-03-07T01:19:05.840 に答える