web-dev-qa-db-fra.com

Simuler la fonction de décalage dans MySQL

| 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  
34
javanx

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:

  1. La clause order by Est importante ici tout comme dans une fonction de fenêtre standard.
  2. Vous pouvez également utiliser le décalage pour company juste pour être sûr que vous calculez la différence entre guillemets du même company.
  3. Vous pouvez également implémenter des compteurs de lignes de la même manière @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.

50
Dojo

Depuis MySQL 8.0 et supérieur, il n'est pas nécessaire de simuler LAG. Il est nativement pris en charge,

Fonction Fenêtre :

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;

Démo DBFiddle

11
Lukasz Szozda

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.

5
vyegorov