2009-09-04 18 views
27

Estoy tratando de buscar el primer y el último registro de un registro 'agrupado'.
Más precisamente, estoy haciendo una consulta como esta¿Cómo recuperar el primer y último registro de un registro agrupado en una consulta MySQL con funciones agregadas?

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

pero me gustaría conseguir el primero y el último disco del grupo. Podría hacerlo al hacer toneladas de solicitudes, pero tengo una tabla bastante grande.

¿Hay alguna forma de hacerlo (con poco tiempo de procesamiento si es posible) con MySQL?

+0

Para mayor eficiencia, ver http://mysql.rjweb.org/doc.php/groupwise_max –

Respuesta

51

que desea utilizar y GROUP_CONCATSUBSTRING_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 

Esto evita costosas consultas sub y me resulta generalmente más eficiente para este problema en particular.

Consulte las páginas del manual de ambas funciones para comprender sus argumentos, o visite este artículo que incluye un ejemplo de cómo hacerlo timeframe conversion in MySQL para obtener más explicaciones.

+0

O cómo salvar una vida. –

+3

¡Gracias por la solución astuta!Aún así, me parece desafortunado que MySQL no admita FIRST() y LAST(), que sería mucho más rápido que esto ... – Aweb

+0

Excelente solución. Me pregunté sobre el rendimiento y las consideraciones de memoria en tablas grandes hasta que vi que la operación está confinada al tamaño definido por 'group_concat_max_len' (valor predeterminado 1024). ¡Buenos tiempos! –

2

intenta esto para empezar ...:

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 
+1

¡Belleza! Necesitaba un mínimo, un máximo para la misma subconsulta que busco. ¡¡Gracias!! – curlyreggie

-1

Suponiendo que desea que los identificadores de los registros con el LOW_PRICE más bajo y el más alto HIGH_PRICE se podría añadir estas dos columnas a la consulta,

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 la eficiencia es un problema, debe agregar una columna para 'year_week', agregar algunos índices de cobertura y dividir la consulta en dos.

La columna 'year_week' es simplemente un INT configurado con el valor de YEARWEEK (date) y se actualiza cada vez que se actualiza la columna 'date'. De esta forma, no tiene que volver a calcularlo para cada consulta y puede indexarlo.

Los nuevos índices de cubierta deberían verse así. El orden es importante. yw_lp_id CLAVE (year_week, LOW_PRICE, id), CLAVE yw_hp_id (year_week, HIGH_PRICE, id)

A continuación, debe utilizar estos dos consultas

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 

y

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 

Cubriendo los índices están bastante útil. Consulte this para obtener más detalles.

0

Aquí hay una gran solución específica para este problema específico: http://topwebguy.com/first-and-last-in-mysql-a-working-solution/ Es casi tan simple como usar FIRST y LAST en MySQL.

voy a incluir el código que realmente ofrece la solución, pero se puede mirar UPI todo el texto:

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; 
Cuestiones relacionadas