Je veux joindre deux tables, mais seulement 1 enregistrement de table2 par enregistrement sur table1
Par exemple:
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
Cela me donnerait tous les enregistrements dans products
, ce qui n'est pas ce que je veux. Je veux 1 [le premier] produit par catégorie (j'ai une colonne sort
dans le champ des produits).
Comment je fais pour faire ça?
J'aime plus une autre approche décrite dans une question similaire: https://stackoverflow.com/a/11885521/2215679
Cette approche est préférable, en particulier si vous devez afficher plusieurs champs dans SELECT. Pour éviter Error Code: 1241. Operand should contain 1 column(s)
ou double sous-sélectionner pour chaque colonne.
Pour votre situation, la requête devrait ressembler à:
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
)
La réponse acceptée par @ goggin13 semble fausse. Les autres solutions fournies à ce jour fonctionneront, mais souffrent du problème n + 1 et, en tant que telles, de la performance.
problème n + 1: s'il y a 100 catégories, il faudrait alors sélectionner 1 pour obtenir les catégories, puis pour chacune des 100 catégories retournées, il faudrait sélectionner pour obtenir les produits de cette catégorie. Ainsi, 101 requêtes SELECT seraient effectuées.
Ma solution alternative résout le problème n + 1 et devrait par conséquent être nettement plus performante puisque seulement 2 sélections sont effectuées.
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
Cela retournera les premières données dans les produits (égal à limite 1)
La clause With ferait l'affaire. Quelque chose comme ça:
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);
Et ça?
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;
Lorsque vous utilisez postgres, vous pouvez utiliser le DISTINCT ON
syntex pour limiter le nombre de colonnes renvoyées par l'une ou l'autre table.
Voici un exemple du code:
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)
L'astuce n'est pas de joindre directement sur la table avec plusieurs occurrences de l'id, mais plutôt de créer d'abord une table avec une seule occurrence pour chaque id
En supposant que vous vouliez un produit avec MIN()
imial value dans la colonne sort
, cela ressemblerait à ceci.
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