MySQL JOIN с LIMIT 1 на объединенной таблице - PullRequest
55 голосов
/ 30 июля 2011

Я хочу объединить две таблицы, но получить только 1 запись таблицы 2 на запись таблицы 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 в поле продуктов).

Как мне это сделать?

Ответы [ 9 ]

59 голосов
/ 27 июня 2014

Мне больше нравится другой подход, описанный в похожем вопросе: 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
 )
21 голосов
/ 04 марта 2015

Принятый ответ от @ 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;
8 голосов
/ 01 октября 2014
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)

2 голосов
/ 15 июня 2016

Предложение 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 голосов
/ 30 июля 2011

Как насчет этого?

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;
0 голосов
/ 12 декабря 2018

При использовании 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)
Хитрость заключается не в том, чтобы соединяться непосредственно в таблице с несколькими вхождениями идентификатора, а, скорее, сначала создать таблицу столько один экземпляр для каждого идентификатора

0 голосов
/ 08 октября 2015

Замените таблицы вашими:

SELECT * FROM works w 
LEFT JOIN 
(SELECT photoPath, photoUrl, videoUrl FROM workmedias LIMIT 1) AS wm ON wm.idWork = w.idWork
0 голосов
/ 30 июля 2011

Я бы попробовал что-то вроде этого:

SELECT C.*,
      (SELECT P.id, P.title 
       FROM products as P
       WHERE P.category_id = C.id
       LIMIT 1)
FROM categories C
0 голосов
/ 30 июля 2011

Если вы хотите, чтобы в столбце 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
...