web-dev-qa-db-ja.com

結合されたテーブルでLIMIT 1を使用したMySQL JOIN

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列があります)。

それをどうやってやるの?

56
John Davidson

同様の質問で説明されている別のアプローチが好きです: 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
 )
62
Kostanos

@ 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;
21
Gravy
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)。

9
Jessé Catrinck

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);
2
la_kal

これはどうですか?

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;
2
Krab

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回だけ出現するテーブルを最初に作成することです

0
Yaki Klein

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
0
Mchl