私は3つのテーブルを持っています:
users(id, account_balance)
grocery(user_id, date, amount_paid)
fishmarket(user_id, date, amount_paid)
fishmarket
とgrocery
の両方のテーブルで、同じuser_idに対して複数のオカレンスがあり、日付と支払い額が異なる場合や、特定のユーザーに対して何もない場合があります。次のクエリを試すと:
SELECT
t1."id" AS "User ID",
t1.account_balance AS "Account Balance",
count(t2.user_id) AS "# of grocery visits",
count(t3.user_id) AS "# of fishmarket visits"
FROM users t1
LEFT OUTER JOIN grocery t2 ON (t2.user_id=t1."id")
LEFT OUTER JOIN fishmarket t3 ON (t3.user_id=t1."id")
GROUP BY t1.account_balance,t1.id
ORDER BY t1.id
不正な結果が生成されます:"1", "12", "12"
。
しかし、1つのテーブルだけをLEFT JOIN
にしようとすると、grocery
またはfishmarket
のどちらの訪問("1", "3", "4"
)でも正しい結果が得られます。
ここで何が悪いのですか?
私はPostgreSQL 9.1を使用しています。
結合は左から右に処理されます(括弧がそれ以外の場合を除きます)。 LEFT JOIN
(または単にJOIN
、同様の効果)の場合、1人のユーザーに3つの食料品を購入すると、3行(1 x 3)。その後、同じユーザーの4つの魚市場に参加すると、12(3 x 4)行、multiplying結果の前のカウントで、期待どおりのaddingではありません。
それにより、食料品や魚市場への訪問数が増加します。
次のように機能するはずです。
SELECT u.id
, u.account_balance
, g.grocery_visits
, f.fishmarket_visits
FROM users u
LEFT JOIN (
SELECT user_id, count(*) AS grocery_visits
FROM grocery
GROUP BY user_id
) g ON g.user_id = u.id
LEFT JOIN (
SELECT user_id, count(*) AS fishmarket_visits
FROM fishmarket
GROUP BY user_id
) f ON f.user_id = u.id
ORDER BY u.id;
1人または少数のユーザーの集計値を検索するには、相関サブクエリ@ Vinceが提供されるように で十分です。テーブル全体またはその主要部分の場合、nテーブルを集計して結果に結合するonceの方が(はるかに)効率的です。この方法では、外部クエリに別のGROUP BY
も必要ありません。
元のクエリの場合、グループ化して事前にグループ化された結果を確認すると、受け取っていたカウントが作成された理由がわかります。
おそらく、サブクエリを利用する次のクエリは、意図した結果を実現するでしょう。
SELECT
t1."id" AS "User ID",
t1.account_balance AS "Account Balance",
(SELECT count(*) FROM grocery t2 ON (t2.user_id=t1."id")) AS "# of grocery visits",
(SELECT count(*) FROM fishmarket t3 ON (t3.user_id=t1."id")) AS "# of fishmarket visits"
FROM users t1
ORDER BY t1.id
これは、ユーザーテーブルが食料品テーブルに結合すると、3つのレコードが一致するためです。次に、これらの3つのレコードのそれぞれが魚市場の4つのレコードと一致し、12のレコードが生成されます。探しているものを取得するにはサブクエリが必要です。