2010-11-16 4 views
4

D'accord, j'ai une table où je dois obtenir la date pertinente d'un groupe en fonction ...SQL MIN (valeur) date correspondant à

Here is a sample of the data: 
min_price, day 
140000  2010-09-26 
130000  2010-09-27 
154991  2010-10-08 
143000  2010-10-09 
156470  2010-10-10 

I would like this result: 
130000  2010-09-27 
143000  2010-10-09 

Here is the SQL I use: 

SELECT MIN(min_price) AS low_price, min_price, day 
FROM compress 
WHERE item_name = '$item' 
GROUP BY EXTRACT(MONTH FROM day), EXTRACT(YEAR FROM day) 

Here is what I get: 
130000  2010-09-26 
143000  2010-10-08 

Comme vous pouvez le voir, les dates ne correspondent pas avec la valeur min row. J'ai besoin d'eux pour correspondre. Quel SQL puis-je utiliser pour obtenir ce résultat?

Répondre

2
Select C.min_price, C.day 
From compress As C 
Where C.item_name = '$item' 
    And Exists (
       Select 1 
       From compress As C2 
       Where C2.item_name = C.item_name 
        And Extract(Month From C2.day) = Extract(Month From C.day) 
        And Extract(Year From C2.day) = Extract(Year From C.day) 
       Group By Extract(Month From C2.day), Extract(Year From C2.day) 
       Having C.min_price = Min(C2.min_price) 
       ) 

AJOUT

MySQL est mieux avec joint alors voici une variante de la même requête

Select C.min_price, C.day 
From compress As C 
    Join (
      Select C2.item_name 
       , Extract(Month From C2.day) As ItemMonth 
       , Extract(Year From C2.day) As ItemYear 
       , Min(C2.min_price) As MinPrice 
      From compress As C2 
      Group By C2.item_num, Extract(Month From C2.day), Extract(Year From C2.day) 
      ) As Z 
     On Z.item_name = C.item_name 
      And Z.ItemMonth = Extract(Month From C.day) 
      And Z.ItemYear = Extract(Year From C.day) 
      And Z.MinPrice = C.min_price 
Where C.item_name = '$item' 

Ce qui est vraiment ralentit toute variation est l'appel de l'extrait sur chaque ligne. Si vous aviez une table de calendrier contenant une ligne pour chaque date et une colonne pour le mois et l'année de la date et de votre table de calendrier a couvert les plages de dates dans vos données, vous pouvez faire quelque chose comme:

Select C.min_price, C.day 
From compress As C 
    Join Calendar As Cal 
     On Cal.Date = C.Day 
    Join (
      Select C3.item_name 
       , Cal3.Month, Cal3.Year 
       , Min(C3.min_price) As MinPrice 
      From compress As C3 
       Join Calendar As Cal3 
        On Cal3.Date = C3.day 
      Group By C3.item_num, Cal3.Month, Cal3.Year 
      ) As Z 
     On Z.item_name = C.Item_name 
      An Z.Month = Cal.Month 
      And Z.Year = Cal.Year 
      And Z.MinPrice = C.min_price 
Where C.item_name = '$item' 
+0

Hmmm ... Ca a l'air de bien fonctionner, même si c'est incroyablement lent ... Je devrais peut-être trouver une autre alternative ... Merci, cependant. – Yoshiyahu

+0

Question rapide ... Serait-il possible de spécifier seulement certains noms d'éléments avec cette requête? – Yoshiyahu

+0

@Yoshiyahu - J'ai fourni quelques variantes qui pourraient être plus rapides qu'une sous-requête. Dans les trois variantes, j'ai fourni pour passer une valeur $ item dans la requête. – Thomas

0
SELECT min_price AS low_price, min_price, day 
FROM compress 
WHERE item_name = '$item' AND min_price = MIN(min_price) 
GROUP BY EXTRACT(MONTH FROM day), EXTRACT(YEAR FROM day) 

Cela puis sélectionnez la ligne où la MIN_PRICE est le même que le MIN (MIN_PRICE)

+2

Les fonctions d'agrégation ne peuvent pas être utilisées dans une clause WHERE et ne renvoient rien avec une clause HAVING. J'ai déjà essayé cela ... – Yoshiyahu

+0

Ensuite, optez pour la solution SELECT imbriquée de Thomas. Je dois admettre qu'un SELECT imbriqué était ma première pensée mais je pensais qu'une solution plus efficace serait possible. – winwaed

0

Votre SQL est pas valide. Lors du regroupement, chaque colonne de la liste d'affichage (qui ne fait pas partie de l'expression group by) doit passer par une fonction d'agrégation, par ex. AVG(), MIN(), MAX() mais vous demandez simplement "jour".

Veuillez indiquer en langage naturel (anglais) ce que vous essayez d'atteindre. Votre exemple n'est pas parfaitement clair.

+0

Ah, ce que j'essaye de faire est d'obtenir le jour où le min_price était à son plus bas chaque mois. Aussi simple que cela. – Yoshiyahu

+0

Ah, ce n'est pas aussi simple que vous le pensez. Et si le produit restait à son point bas pendant plusieurs jours? Voulez-vous le premier jour de la série ou le dernier? – Tim

0

Si Je comprends bien le problème, cela devrait fonctionner ...

mysql> select * from stack; 
+-----------+------------+ 
| min_price | myday  | 
+-----------+------------+ 
| 140000 | 2010-09-26 | 
| 130000 | 2010-09-27 | 
| 154991 | 2010-10-08 | 
| 143000 | 2010-10-09 | 
| 156470 | 2010-10-10 | 
+-----------+------------+ 
5 rows in set (0.00 sec) 

mysql> select a.* from stack as a inner join 
    -> (select min(min_price) as my_price from stack group by extract(YEAR_MONTH from myday)) as b 
    -> on a.min_price = b.my_price; 
+-----------+------------+ 
| min_price | myday  | 
+-----------+------------+ 
| 130000 | 2010-09-27 | 
| 143000 | 2010-10-09 | 
+-----------+------------+ 
2 rows in set (0.00 sec) 

Vous devrez joindre à une clé primaire afin d'éviter des résultats inattendus. Si la requête est lente, créez une table temporaire pour subselect, générez des index sur celle-ci, puis utilisez la table pour joindre à la table principale.

Questions connexes