soporta - optimizar consultas lentas mysql
Simular la funciĆ³n de retardo en MySQL (3)
| 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 |
¿Cómo hago un retraso en esta tabla en MySQL para imprimir la diferencia entre comillas, por ejemplo:
GOOGLE | 20
SAP | 40
Desde MySQL 8.0 y superior no hay necesidad de simular LAG
. Es nativamente compatible,
Devuelve el valor de expr de la fila que retrasa (precede) la fila actual en N filas dentro de su partición. Si no existe dicha fila, el valor de retorno es el predeterminado. Por ejemplo, si N es 3, el valor de retorno es el predeterminado para las primeras dos filas. Si falta N o valor predeterminado, los valores predeterminados son 1 y NULL, respectivamente.
SELECT
company,
quote,
LAG(quote) OVER(PARTITION BY company ORDER BY time) AS prev_quote
FROM tab;
Este es mi truco MySQL favorito.
Así es como se emula la función de retraso:
SET @quot=-1;
select time,company,@quot lag_quote, @quot:=quote curr_quote
from stocks order by company,time;
-
lag_quote
contiene el valor de la cita de la fila anterior. Para la primera fila @quot es -1. -
curr_quote
contiene el valor de la cita de la fila actual.
Notas:
-
order by
cláusula es importante aquí al igual que en una función de ventana normal. - También es posible que desee utilizar lag para la
company
solo para asegurarse de que está calculando la diferencia en las cotizaciones de la mismacompany
. - También puede implementar contadores de fila de la misma manera
@cnt:=@cnt+1
Lo bueno de este esquema es que es computacionalmente muy delgado en comparación con algunos otros enfoques, como el uso de funciones agregadas, procedimientos almacenados o procesamiento de datos en el servidor de aplicaciones.
EDITAR:
Ahora viene su pregunta de obtener el resultado en el formato que mencionó:
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;
La anidación no está relacionada, por lo que no es tan mala (computacionalmente) como parece (sintácticamente) :)
Avíseme si necesita ayuda con esto.
Para lograr el resultado deseado, primero debe encontrar la última y la próxima marca de tiempo para cada compañía. Es bastante simple con la siguiente consulta:
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;
Ahora debe unirse a esta subconsulta con la tabla original para obtener los resultados deseados:
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;
Puede observar los resultados en SQL Fiddle .
Esta consulta usa solo capacidades estándar de SQL y debería funcionar en cualquier RDBMS.