2つのテーブルを結合したいが、table1のレコードごとにtable2のレコードを1つだけ取得する
例えば:
SELECT c.id, c.title, p.id AS product_id, p.title
FROM categories AS c
JOIN products AS p ON c.id = p.category_id
これにより、products
内のすべてのレコードが取得されますが、これは必要なものではありません。カテゴリごとに1 [最初の]製品が必要です(製品フィールドにsort
列があります)。
それをどうやってやるの?
同様の質問で説明されている別のアプローチが好きです: https://stackoverflow.com/a/11885521/2215679
このアプローチは、特にSELECTで複数のフィールドを表示する必要がある場合に適しています。 Error Code: 1241. Operand should contain 1 column(s)
を回避するか、各列の二重副選択を行います。
あなたの状況では、クエリは次のようになります。
SELECT
c.id,
c.title,
p.id AS product_id,
p.title AS product_title
FROM categories AS c
JOIN products AS p ON
p.id = ( --- the PRIMARY KEY
SELECT p1.id FROM products AS p1
WHERE c.id=p1.category_id
ORDER BY p1.id LIMIT 1
)
@ goggin13が受け入れた答えは間違っているようです。これまでに提供された他のソリューションも機能しますが、n + 1の問題が発生するため、パフォーマンスが低下します。
n + 1の問題:100個のカテゴリーがある場合、カテゴリーを取得するために1回選択する必要があり、返された100個のカテゴリーごとに、そのカテゴリーの製品を取得するために選択する必要があります。したがって、101のSELECTクエリが実行されます。
私の代替ソリューションはn + 1の問題を解決し、結果として2つの選択のみが実行されるため、パフォーマンスが大幅に向上するはずです。
SELECT
*
FROM
(SELECT c.id, c.title, p.id AS product_id, p.title
FROM categories AS c
JOIN products AS p ON c.id = p.category_id
ORDER BY c.id ASC) AS a
GROUP BY id;
SELECT c.id, c.title, p.id AS product_id, p.title
FROM categories AS c
JOIN products AS p ON c.id = p.category_id
GROUP BY c.id
これにより、製品の最初のデータが返されます(等しい制限1)。
With句がトリックを行います。このようなもの:
WITH SELECTION AS (SELECT id FROM products LIMIT 1)
SELECT a.id, c.id, c.title FROM selection a JOIN categories c ON (c.id = a.id);
これはどうですか?
SELECT c.id, c.title, (SELECT id from products AS p
WHERE c.id = p.category_id
ORDER BY ...
LIMIT 1)
FROM categories AS c;
Postgresを使用する場合、_DISTINCT ON
_シンテックスを使用して、いずれかのテーブルから返される列の数を制限できます。
コードのサンプルは次のとおりです。
SELECT c.id, c.title, p.id AS product_id, p.title FROM categories AS c JOIN ( SELECT DISTINCT ON(p1.id) id, p1.title, p1.category_id FROM products p1 ) p ON (c.id = p.category_id)
トリックは、IDが複数回出現するテーブルに直接参加するのではなく、各IDに対して1回だけ出現するテーブルを最初に作成することです
sort
列にMIN()
imial値を持つ製品が必要だとすると、このようになります。
SELECT
c.id, c.title, p.id AS product_id, p.title
FROM
categories AS c
INNER JOIN (
SELECT
p.id, p.category_id, p.title
FROM
products AS p
CROSS JOIN (
SELECT p.category_id, MIN(sort) AS sort
FROM products
GROUP BY category_id
) AS sq USING (category_id)
) AS p ON c.id = p.category_id