私はPostgresを使用しています。これは、SELECT ... GROUP BYのすべての列がGROUP BY句に表示されるか、集計関数で使用される必要があるという制約を適用します。
人の車をモデル化していて、人の名前、免許番号、車の台数を調べたいとしましょう。これが SQL Fiddle としての私の例です。
次のスキーマがあります:
CREATE TABLE person(
id integer PRIMARY KEY,
name text
);
CREATE TABLE license(
person_id integer REFERENCES person(id),
expiry_date date
);
CREATE TABLE car(
owner_id integer REFERENCES person(id),
registration_number TEXT
);
これがクエリです:
SELECT person.name, person.id, license.expiry_date, COUNT(car) FROM person
JOIN license ON license.person_id = person.id
JOIN car ON car.owner_id = person.id
WHERE person.name = 'Charles Bannerman'
GROUP BY person.id;
私は知っています、私自身のビジネスロジックのため、その1人は1つのライセンスしか持てないので、その人に加わると、それがGROUP BYであったとしても、私は彼らのライセンス番号を見つけることができるはずです。ただし、これはGROUP BYステートメントの一部ではなく、集計関数を使用しないため、アクセスできません。
このクエリを慣用的な方法でどのように記述すればよいですか。 LATERAL JOIN、ウィンドウ関数、サブクエリについて漠然としたことを見てきましたが、この質問に答える最善の方法はわかりません。
あなたは出来る GROUP BY
結合を行う前に...つまり、クエリを逆にします。
これはあなたの古いクエリです
SELECT person.name, person.id, license.expiry_date, COUNT(car) FROM person
JOIN license ON license.person_id = person.id
JOIN car ON car.owner_id = person.id
WHERE person.name = 'Charles Bannerman'
GROUP BY person.id;
これはあなたの新しいクエリです
WITH vals AS (
SELECT owner_id, COUNT(car) AS cars FROM car GROUP BY owner_id
) SELECT
person.name, person.id, license.expiry_date, vals.cars
FROM cars
JOIN person ON cars.owner_id = person.id
JOIN license ON person.id = license.person_id
WHERE person.name = 'Charles Bannerman';
その解決策は、あなたが望むほど効率的ではないかもしれません...別の潜在的な解決策は、person_idが指定されたときに自動車の数を返すplpgsql関数を記述することです。
私が選択するソリューションは、クエリの使用例によって異なります。クエリは常に(特定の人の)データの単一行を返すために使用されますか?または、レポートで多数の行を表示するために使用されますか? ?..
seharusnya seperti ini(このようになっているはずです):
SELECT person.name, person.id, license.expiry_date, COUNT(car) FROM person
JOIN license ON license.person_id = person.id
JOIN car ON car.owner_id = person.id
WHERE person.name = 'Charles Bannerman'
GROUP BY person.name, person.id, license.expiry_date, car.car;
_SELECT person.name,
person.id,
license.expiry_date, COUNT(car) OVER (Partition by Person.Id)
FROM person
JOIN license ON license.person_id = person.id
JOIN car ON car.owner_id = person.id
WHERE person.name = 'Charles Bannerman';
_
OVER (partion by <grouping column(s)>)
を使用できます。これにより、Group byを使用せずにデータが集計されます。
これの唯一の欠点は、重複する_Person.id
_と_license.expiry_date
_がある場合、2つの結果が得られることです。ただし、_group by
_の一部でなくても、他のデータを追加できます。ちょっとした考え。