2010-07-27 6 views
15

Prenons le cas de deux tables: tbl_product et tbl_transaction.
tbl_product listes Détails du produit, y compris les noms et ids tandis que tbl_transaction énumère les opérations portant sur les produits et comprend les dates, les produits-ids, les clients, etc.Comment limiter les résultats d'un LEFT JOIN

je dois afficher une page Web montrant 10 produits et pour chaque produit, le dernier 5 transactions. Jusqu'à présent, aucune requête LEFT JOIN ne semble fonctionner et la sous-requête ci-dessous aurait fonctionné si mysql pouvait autoriser la partie tx.product_id=ta.product_id (échoue avec Colonne inconnue 'ta.product_id' dans 'clause where': [ERREUR: 1054]).

SELECT 
ta.product_id, 
ta.product_name, 
tb.transaction_date 
FROM tbl_product ta 
LEFT JOIN (SELECT tx.transaction_date FROM tbl_transaction tx WHERE tx.product_id=ta.product_id LIMIT 5) tb 
LIMIT 10 

Est-il possible d'obtenir la liste que j'ai besoin sans utiliser plusieurs requêtes dans une boucle?

Edit:
C'est exactement ce que je dois de MySQL:

SELECT ta.product_id, ta.product_name, tb.transaction_date ... 
FROM tbl_product ta 
LEFT JOIN tbl_transaction tb ON (tb.product_id=ta.product_id LIMIT 5) 
LIMIT 10 

Bien sûr, cela est illégal, mais je veux vraiment que ce n'était pas!

+0

Vous n'avez aucune clause "ON" pour votre jointure? –

+0

Même avec la clause ON, il récupère toujours plus de 5 transactions. Si je supprime le 'tx.product_id = ta.product_id' et que je le modifie en' LEFT JOIN (* mes limites sql *) tb ON tb.product_id = ta.product_id', toujours pas ce que je veux ~ –

+0

Est-ce que votre table de transaction 'tbl_transaction 'avoir un identifiant? – gnarf

Répondre

6

C'est là que les fonctions de classement seraient très utiles. Malheureusement, MySQL ne les supporte pas encore. Au lieu de cela, vous pouvez essayer quelque chose comme le suivant.

Select ta.product_id, ta.product_name 
    , tb.transaction_date 
From tbl_product As ta 
    Left Join (
       Select tx1.product_id, tx1.transaction_id, tx1.transaction_date 
        , (Select Count(*) 
         From tbl_transaction As tx2 
         Where tx2.product_id = tx1.product_id 
          And tx2.transaction_id < tx1.transaction_id) As [Rank] 
       From tbl_transaction As tx1 
       ) as tb 
     On tb.product_id = ta.product_id 
      And tb.[rank] <= 4 
Limit 10 
+0

Merci pour la réponse, Thomas. Oui, 'tbl_transaction' a une colonne AUTO_INCREMENT comme clé primaire. J'ai essayé votre proposition (bien que je ne la comprenne pas complètement) et j'ai eu une liste des produits mais ** sans aucune ** transaction. Pourquoi l'auto-jointure (sur tbl_transaction [tx> -

+0

@eddy edu - L'essentiel est d'imposer un classement sur les transactions par produit. À cette fin, je compare la table de transactions par rapport à elle-même pour trouver le nombre de transactions pour un produit donné plus tôt qu'une ligne donnée. La première ligne pour un produit devrait produire un compte de zéro. Maintenant, si vous obtenez des résultats bizarres, j'ai quelques questions. Premièrement, la date de transaction peut-elle être nulle? Deuxièmement, la date de transaction peut-elle être dupliquée (deux lignes pour le même id_produit et la même date)? – Thomas

+1

transaction_date ne peut pas être NULL. transaction_date peut être dupliqué (un produit peut avoir plusieurs transactions pour une date donnée). J'ai besoin de classer les transactions par produit (pour pouvoir regrouper mes transactions par produits), j'ai juste besoin de voir comment la colonne date entre. –

-2

Vous devez retirer la condition de jointure de votre sous-requête. Essayez:

SELECT 
    ta.product_id, 
    ta.product_name, 
    tb.transaction_date 
FROM tbl_product ta 
LEFT JOIN (SELECT tx.transaction_date 
      FROM tbl_transaction tx 
      ORDER BY tx.transaction_date DESC 
      LIMIT 5) tb 
ON ta.product_id=tb.product_id 
LIMIT 10 
+1

Celle-ci fonctionne mais LIMITE seulement le premier produit. –

+2

Cela ne fonctionne pas car votre sous-requête ne renvoie que les 5 dernières transactions pour TOUTES les transactions. Il a déclaré "pour chaque produit, les 5 dernières transactions". – nategood

1

Il échoue parce que quand vous mettez entre parenthèses autour de votre requête et lui donner l'alias « tb » vous avez créé une table dérivée. Votre table dérivée n'a pas connaissance de l'alias ayant de table tbl_product "ta"

Essayez d'utiliser ON ou WHERE à l'extérieur de la table dérivée, référence alors que le tableau en utilisant l'alias "tb" vous avez fourni

EDIT:

L'utilisation de "LIMIT" limite les résultats de la requête dans son intégralité. Alors que vous avez "LIMIT 10" ce que vous voulez réellement est de 50 lignes (ou moins s'il y en a moins de 5 historiques), n'est-ce pas?

10 produits, joints à 5 enregistrements historiques, retournant 50 lignes au total.

Dans ce cas, vous pouvez avoir une seule solution d'interrogation se joindre à lui-même la table de produit dans une table dérivée ayant « LIMIT 10 »

Tels que:

SELECT * 
FROM tbl_product ta 
JOIN (SELECT * FROM tbl_product tz WHERE tz.product_id = ta.product_id LIMIT 10) tc 
LEFT JOIN (SELECT tx.transaction_date FROM tbl_transaction tx 
    WHERE tx.product_id=ta.product_id LIMIT 5) tb 

Vous pourriez nous aussi " dans » et préciser le top 10 tels que:

SELECT * 
FROM tbl_product ta 
LEFT JOIN (SELECT tx.transaction_date FROM tbl_transaction tx 
WHERE tx.product_id=ta.product_id LIMIT 5) tb 
WHERE ta.product_id IN 
    (SELECT z.product_id FROM tbl_product z LIMIT 10) 
+0

Après avoir modifié (en supprimant la référence tbl_product dans la sous-requête et en l'ajoutant dans une clause ON) la requête fonctionne bien mais la LIMITE ne semble s'appliquer qu'au premier produit, c'est-à-dire que j'obtiens une liste de 10 transactions mais tous les autres n'en ont pas. –

+0

Encore une fois la réponse est parce que si votre table dérivée. La "LIMIT" dans la table dérivée n'est pas liée à la "LIMIT" dans la requête entière. Que diriez-vous de quelques données d'échantillon? – Matthew

+0

Edité ma réponse pour mieux expliquer – Matthew

0

Edit:

Si vous voulez imposer une limite sur chaque produit, je le séparer en deux requêtes.

D'abord, obtenez une liste de 10 produits, puis lancez une autre requête pour chacun de ceux qui retournent les cinq dernières transactions.

+0

Celui-ci échoue avec une erreur cryptique qui est seulement fixée en ayant une clause ON. Et après le 'correctif', le jeu de résultats ne contient que le premier produit avec 5 transactions - les autres produits sont ignorés. –

+0

J'ai considéré cela mais je suis sûr qu'il y a une solution à une question à cela! Il doit juste y avoir! –