2012-07-17 13 views
5

Estoy tratando de encontrar el primer valor más bajo en una tabla y la fecha en que ocurre, para cada usuario DISTINCT en una tabla.Obteniendo el PRIMER valor más bajo en la tabla y la fecha en que ocurre, para cada usuario distinto

Este es el esquema de tablas y algunos datos de la muestra:

CREATE TABLE diet_watch (
    entry_date date NOT NULL, 
    user_id int default 1, 
    weight  double precision NOT NULL 
); 

INSERT INTO diet_watch VALUES ('2001-01-01', 1, 128.2); 
INSERT INTO diet_watch VALUES ('2001-01-02', 1, 121.0); 
INSERT INTO diet_watch VALUES ('2001-01-03', 1, 122.3); 
INSERT INTO diet_watch VALUES ('2001-01-04', 1, 303.7); 
INSERT INTO diet_watch VALUES ('2001-01-05', 1, 121.0); 
INSERT INTO diet_watch VALUES ('2001-01-01', 2, 121.0); 
INSERT INTO diet_watch VALUES ('2001-01-06', 2, 128.0); 

El SQL que se me ocurrió es aquí en this snippet

que ya han informado de que es incorrecta, tal vez alguien puede explicar lo el problema con mi SQL es?

Nota: Preferiría ANSI SQL si fuera posible, pero estoy usando PostgreSQL, así que si tengo que usar un sabor específico de SQL, tiene que funcionar en PG.

+0

no puedo llegar a tocar el violín SQL en este momento. ¿Puedes publicar tu consulta? – RedFilter

+0

@RedFilter - ¿SQL Fiddle no funciona para usted? ¿Que esta pasando? –

+0

@JakeFeasel Está bien ahora - Creo que el servidor estaba siendo golpeado duro, la página tardó un par de minutos en renderizarse. Pero estuvo bien después de eso. – RedFilter

Respuesta

6

Nota: No estoy seguro si las funciones de ventana son ANSI SQL

funciones de la ventana son una parte del SQL: 2003 especificación: http://en.wikipedia.org/wiki/Window_function_%28SQL%29#Window_function (Thx @a_horse_with_no_name)

Prueba esto:

http://sqlfiddle.com/#!1/7aa4e/22

SELECT * 
    FROM 
    (
    SELECT a.*, 
      ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY weight) AS Position 
     FROM diet_watch a 

    ) a 
    WHERE a.Position = 1 
+0

Sí, las funciones de ventana ** son ** ANSI SQL (desde 2003). –

+0

@a_horse_with_no_name Estaba tratando de obtener una referencia en línea para publicar aquí.Si eres útil, ¿puedes publicarlo? – Chandu

+0

http://en.wikipedia.org/wiki/Window_function_%28SQL%29#Window_function –

1

Primero, su consulta es innecesariamente complicada. Puede simplemente colocar al grupo en la subconsulta y eliminar la consulta externa.

La función de Windows, mencionada por @Chandu, es una muy buena solución. Es ANSI SQL y postgres lo admite. Sin embargo, no todas las bases de datos lo hacen. Una alternativa es:

select dw.* 
from diet_watch dw join 
    (select user_id, min(entry_date) as mindate 
     from diet_watch dw 
     group by user_id 
    ) dwmin 
    on dw.user_id = dwmin.user_id and dw.entry_date = dwmin.mindate 

El motivo por el que su consulta original no funciona es porque el mínimo entry_date puede no tener el peso mínimo. Su consulta recupera el mínimo de cada campo de forma independiente. Esta versión encuentra la fecha mínima, luego la une a la tabla original para obtener el peso (y otra información) ese día.

+0

En realidad, casi todas las funciones de ventanas de soporte DBMS. Hay muy pocos que no lo hacen (notablemente MySQL y SQLite) –

+0

+1, principalmente por la explicación de por qué falla la consulta de PO. – dbenham

1

Si está buscando la primera vez que cada usuario alcanza su peso mínimo, creo que esto funciona. Veo en los datos de prueba, el usuario 1 alcanza su mínimo de 121 dos veces, ¿y desea la primera fecha? Que yo sepa, esto debería funcionar en todos los motores SQL.

SELECT min(dw.entry_date), dw.user_id, dw.weight FROM diet_watch dw, 
    (SELECT min(weight) AS "weight", user_id FROM diet_watch GROUP BY user_id) mins 
WHERE dw.user_id = mins.user_id AND dw.weight = mins.weight 
GROUP BY dw.user_id, dw.weight 

La selección interna encuentra el peso mínimo de cada usuario. Otro minuto es necesario en la fecha, porque de lo contrario no seleccionaría específicamente la primera vez que se logró ese peso mínimo para ese usuario.

http://sqlfiddle.com/#!1/7aa4e/51/0

Cuestiones relacionadas