| time | company | quote |
+---------------------+---------+-------+
| 0000-00-00 00:00:00 | GOOGLE | 40 |
| 2012-07-02 21:28:05 | GOOGLE | 60 |
| 2012-07-02 21:28:51 | SAP | 60 |
| 2012-07-02 21:29:05 | SAP | 20 |
Comment puis-je faire un décalage sur cette table dans MySQL pour imprimer la différence entre guillemets, par exemple:
GOOGLE | 20
SAP | 40
Ceci est mon hack MySQL préféré.
Voici comment vous émulez la fonction lag:
SET @quot=-1;
select time,company,@quot lag_quote, @quot:=quote curr_quote
from stocks order by company,time;
lag_quote
Contient la valeur du devis de la ligne précédente. Pour la première ligne, @quot est -1.curr_quote
Contient la valeur du devis de la ligne actuelle.Remarques:
order by
Est importante ici tout comme dans une fonction de fenêtre standard.company
juste pour être sûr que vous calculez la différence entre guillemets du même company
.@cnt:=@cnt+1
La bonne chose à propos de ce schéma est qu'il est très léger en termes de calcul par rapport à d'autres approches telles que l'utilisation de fonctions d'agrégation, de procédures stockées ou de traitement de données dans le serveur d'applications.
ÉDITER:
Venons-en maintenant à votre question d'obtenir des résultats dans le format que vous avez mentionné:
SET @quot=0,@latest=0,company='';
select B.* from (
select A.time,A.change,IF(@comp<>A.company,1,0) as LATEST,@comp:=A.company as company from (
select time,company,quote-@quot as change, @quot:=quote curr_quote
from stocks order by company,time) A
order by company,time desc) B where B.LATEST=1;
L'imbrication n'est pas co-liée donc pas aussi mauvaise (sur le plan informatique) qu'elle en a l'air (syntaxiquement) :)
Faites-moi savoir si vous avez besoin d'aide à ce sujet.
Depuis MySQL 8.0 et supérieur, il n'est pas nécessaire de simuler LAG
. Il est nativement pris en charge,
Renvoie la valeur de expr à partir de la ligne qui est en retard (précède) la ligne actuelle de N lignes dans sa partition. S'il n'y a pas une telle ligne, la valeur de retour est par défaut. Par exemple, si N est 3, la valeur de retour est par défaut pour les deux premières lignes. Si N ou défaut sont manquants, les valeurs par défaut sont 1 et NULL, respectivement.
SELECT
company,
quote,
LAG(quote) OVER(PARTITION BY company ORDER BY time) AS prev_quote
FROM tab;
Pour obtenir le résultat souhaité, vous devez d'abord trouver les derniers et avant-derniers horodatages de chaque entreprise. C'est assez simple avec la requête suivante:
SELECT c.company, c.mts, max(l.ts) AS lts
FROM (SELECT company, max(ts) AS mts FROM cq GROUP BY company) AS c
LEFT JOIN cq l
ON c.company = l.company AND c.mts > l.ts
GROUP BY c.company, c.mts;
Vous devez maintenant joindre cette sous-requête à la table d'origine pour obtenir les résultats souhaités:
SELECT c.company, l.quote, coalesce(l1.quote, 0),
(l.quote - coalesce(l1.quote, 0)) AS result
FROM (SELECT c.company, c.mts, max(l.ts) AS lts
FROM (SELECT company, max(ts) AS mts FROM cq GROUP BY company) AS c
LEFT JOIN cq l
ON c.company = l.company AND c.mts > l.ts
GROUP BY c.company, c.mts) AS c
LEFT JOIN cq AS l ON l.company = c.company AND l.ts = c.mts
LEFT JOIN cq AS l1 ON l1.company = c.company AND l1.ts = c.lts;
Vous pouvez observer les résultats sur SQL Fiddle .
Cette requête utilise uniquement des capacités SQL standard et devrait fonctionner sur n'importe quel SGBDR.