Comment récupérer le premier et le dernier enregistrement d'un enregistrement groupé dans une requête MySQL avec des fonctions agrégées?

j'essaie de récupérer le premier et le dernier enregistrement d'un enregistrement "groupé".

Plus précisément, je fais une requête comme celle-ci

SELECT MIN(low_price), MAX(high_price), open, close
FROM symbols
WHERE date BETWEEN(.. ..)
GROUP BY YEARWEEK(date)

mais j'aimerais obtenir le premier et le dernier enregistrement du groupe. Il pourrait en fait en faisant des tonnes de demandes mais j'ai une très grande table.

y a-t-il un moyen (si possible un faible temps de traitement) de faire cela avec MySQL?

28
demandé sur Nikita G. 2009-09-04 18:20:14

4 réponses

vous voulez utiliser GROUP_CONCAT et SUBSTRING_INDEX:

SUBSTRING_INDEX( GROUP_CONCAT(CAST(open AS CHAR) ORDER BY datetime), ',', 1 ) AS open
SUBSTRING_INDEX( GROUP_CONCAT(CAST(close AS CHAR) ORDER BY datetime DESC), ',', 1 ) AS close 

cela évite les requêtes sub coûteuses et je le trouve généralement plus efficace pour ce problème particulier.

consultez les pages de manuel des deux fonctions pour comprendre leurs arguments, ou visitez cet article qui comprend un exemple de comment faire conversion des délais en MySQL pour plus d'explications.

51
répondu Joao Costa 2016-06-15 18:13:19

essayez ceci pour commencer... :

Select YearWeek, Date, Min(Low_Price), Max(High_Price)
From
   (Select YEARWEEK(date) YearWeek, Date, LowPrice, High_Price
    From Symbols S
    Where Date BETWEEN(.. ..)
    GROUP BY YEARWEEK(date)) Z
Group By YearWeek, Date
2
répondu Charles Bretana 2009-09-04 14:30:13

Voici une grande solution spécifique à ce problème spécifique: http://topwebguy.com/first-and-last-in-mysql-a-working-solution/ C'est presque aussi simple que D'utiliser le premier et le dernier dans MySQL.

je vais inclure le code qui fournit en fait la solution, mais vous pouvez regarder upi de l'ensemble du texte:

SELECT
word ,  

(SELECT a.ip_addr FROM article a
WHERE a.word = article.word
ORDER BY a.updated  LIMIT 1) AS first_ip,

(SELECT a.ip_addr FROM article a
WHERE a.word = article.word
ORDER BY a.updated DESC LIMIT 1) AS last_ip

FROM notfound GROUP BY word;
0
répondu webmaster 2012-05-26 00:10:22

en supposant que vous voulez les ID des enregistrements avec le plus bas prix et le plus haut prix, vous pouvez ajouter ces deux colonnes à votre requête,

SELECT 

(SELECT id ORDER BY low_price ASC LIMIT 1) low_price_id,
(SELECT id ORDER BY high_price DESC LIMIT 1) high_price_id,

MIN(low_price), MAX(high_price), open, close
FROM symbols
WHERE date BETWEEN(.. ..)
GROUP BY YEARWEEK(date)

si l'efficacité est un problème, vous devez ajouter une colonne pour 'year_week', ajouter quelques index de couverture, et diviser la requête en deux.

la colonne' year_week 'est juste un INT défini à la valeur de YEARWEEK(date) et mis à jour chaque fois que la colonne' date ' est mise à jour. De cette façon, vous n'avez pas à recalculer pour chaque requête et vous pouvez l'index.

les nouveaux index de couverture devraient ressembler à ceci. L'ordre est important. KEY yw_lp_id (year_week, low_price, id), KEY yw_hp_id (year_week, high_price, id)

vous devriez alors utiliser ces deux requêtes

SELECT 
(SELECT id ORDER BY low_price ASC LIMIT 1) low_price_id,
MIN(low_price), open, close
FROM symbols
WHERE year_week BETWEEN(.. ..)
GROUP BY year_week

et

SELECT 
(SELECT id ORDER BY high_price DESC LIMIT 1) high_price_id,
MAX(high_price), open, close
FROM symbols
WHERE year_week BETWEEN(.. ..)
GROUP BY year_week

les index de couverture sont assez utiles. Vérifier pour plus de détails.

-1
répondu james.c.funk 2009-09-06 05:22:18