SQL - Como obtener varios valores superiores en una tabla?

 
Vista:
sin imagen de perfil
Val: 37
Ha mantenido su posición en SQL (en relación al último mes)
Gráfica de SQL

Como obtener varios valores superiores en una tabla?

Publicado por Jorge (19 intervenciones) el 10/07/2018 03:43:15
Saludos!

Estoy atascado en el siguiente problema.
En SQL Server 2014

Tengo una tabla Inventario, donde se guardan los valores calculados de los saldos
si ordeno la tabla en una consulta obtengo el resultado que se muestra en la figura.

¿Como se podría hacer para que la consulta de como resultado solo los valores superiores
por cada producto (es decir solo las que estan marcadas con el punto ROJO)
algo así como un Top 1 pero de cada producto y que luego se unan y se ordenen por código

Tengo unas ideas, pero todavía están muy difusas y no lo puedo plasmar

Gracias.

La consulta de la figura es la siguiente

1
2
3
select Codigo, Nombre, SaldoCant, SaldoValor, Fecha, Registro, CodInterno
from Inventario
ORDER BY Codigo, Fecha desc, Registro desc, CodInterno desc

bn5XdcM
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
Imágen de perfil de gilman
Val: 184
Ha mantenido su posición en SQL (en relación al último mes)
Gráfica de SQL

Como obtener varios valores superiores en una tabla?

Publicado por gilman (103 intervenciones) el 10/07/2018 09:02:47
Prueba:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SELECT Inventario.Codigo,
         Inventario.Nombre,
         Inventario.SaldoCant,
         Inventario.SaldoValor,
         Inventario.Fecha,
         Inventario.Registro,
         Inventario.CodInterno
    FROM Inventario,
         (  SELECT Codigo,
                   MAX (Fecha) MAXFECHA,
                   MAX (Registro) MAXREGISTRO,
                   MAX (CodInterno) MAXCODINTERNO
              FROM Inventario
          GROUP BY Codigo) ENLACE
   WHERE     Inventario.Codigo = ENLACE.Codigo
         AND Inventario.Fecha = ENLACE.MAXFECHA
         AND Inventario.Registro = ENLACE.MAXREGISTRO
         AND Inventario.CodInterno = ENLACE.MAXCODINTERNO
ORDER BY Codigo
Debería funcionar, no tengo SQL Server, el principal problema puede estar en el rendimiento.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
sin imagen de perfil
Val: 37
Ha mantenido su posición en SQL (en relación al último mes)
Gráfica de SQL

Como obtener varios valores superiores en una tabla?

Publicado por Jorge (19 intervenciones) el 10/07/2018 20:11:59
Gracias por responder!

Casi, pero

la consulta tienen un orden progresivo
Fecha desc, Registro desc, CodInterno desc

eh, como lo explico, digamos que tengo esta tabla:
1
2
3
4
5
6
7
Codigo|Saldo|Fecha     |Registro|CodInterno
------+-----+----------+--------+----------
  A   |100  |2018/04/20|   B1   |   4
  A   |200  |2018/04/21|   A1   |   1
  A   |300  |2018/04/20|   C2   |   2
  A   |400  |2018/04/20|   B1   |   5
  B   |500  |2018/04/20|   A1   |   3

Ordenado de mayor a menor por
Fecha > Registro > CodInterno
Sería
1
2
3
4
5
6
7
Codigo|Saldo|Fecha     |Registro|CodInterno
------+-----+----------+--------+----------
  A   |200  |2018/04/21|   A1   |   1
  A   |300  |2018/04/20|   C2   |   2
  A   |400  |2018/04/20|   B1   |   5
  A   |100  |2018/04/20|   B1   |   4
  B   |500  |2018/04/20|   A1   |   3

Si hago la subconsulta con MAX me mostraría los valores máximos de forma indistinta
MAX(Fecha), MAX(Registro), MAX(CodInterno)

y saldría algo así (mostrando el MAX de fecha, el MAX de Registro y el MAX de CodInterno)
agrupado por Codigo
1
2
3
4
Codigo|Fecha     |Registro|CodInterno
------+----------+--------+----------
  A   |2018/04/21|   C2   |   5
  B   |2018/04/20|   A1   |   3

y al momento de hacer la comparación en la consulta principal, no encontraría ningún valor para el Producto "A" que coincida con
Fecha: 2018/04/21 AND
Registro:C2 AND
CodInterno:5
Solo me mostraría el Producto "B" que en este caso por mera coincidencia si habría punto de comparación

Pero
El resultado que busco es como el ordenado por
Fecha > Registro > CodInterno
pero solo los primeros valores código
Así
1
2
3
4
Codigo|Saldo|Fecha     |Registro|CodInterno
------+-----+----------+--------+----------
  A   |200  |2018/04/21|   A1   |   1
  B   |500  |2018/04/20|   A1   |   3

seguiré probando.

Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 806
Bronce
Ha mantenido su posición en SQL (en relación al último mes)
Gráfica de SQL

Como obtener varios valores superiores en una tabla?

Publicado por leonardo_josue (1175 intervenciones) el 11/07/2018 16:32:14
Hola Jorge:

Este tipo de consultas la hemos tratado muchas veces en el foto, porque es una de las de "cajón" que debes de saber... en realidad tienes muchas formas de resolverla, pero en lo particular, considero que la más óptima es con un INNER JOIN y subconsultas. Sería más o menos así:

Tomando como ejemplo los datos que pones en tu segundo post:

1
2
3
4
5
6
7
8
9
10
11
mysql> select * from tabla;
+--------+-------+------------+----------+------------+
| Codigo | Saldo | Fecha      | Registro | CodInterno |
+--------+-------+------------+----------+------------+
| A      |   100 | 2018-04-20 | B1       |          4 |
| A      |   200 | 2018-04-21 | A1       |          1 |
| A      |   300 | 2018-04-20 | C2       |          2 |
| A      |   400 | 2018-04-20 | B1       |          5 |
| B      |   500 | 2018-04-20 | A1       |          3 |
+--------+-------+------------+----------+------------+
5 rows in set (0.00 sec)

A ti te interesa la obtener para cada código el registro con la última fecha es decir la MAXIMA FECHA asociada a ese código, entonces, primero obtienes esos datos mediante una consulta simple:

1
2
3
4
5
6
7
8
9
10
mysql> select codigo, max(fecha) max_fecha
    -> from tabla
    -> group by codigo;
+--------+------------+
| codigo | max_fecha  |
+--------+------------+
| A      | 2018-04-21 |
| B      | 2018-04-20 |
+--------+------------+
2 rows in set (0.00 sec)

Entonces, simplemente utilizas estos resultados para filtrar tu tabla principal, la manera más simple es con un INNER JOIN:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> select T1.*
    -> from tabla T1
    -> inner join
    -> ( select codigo, max(fecha) max_fecha
    ->   from tabla
    ->   group by codigo ) T2
    -> on T1.codigo = T2.codigo and
    ->    T1.fecha = T2.max_fecha;
+--------+-------+------------+----------+------------+
| Codigo | Saldo | Fecha      | Registro | CodInterno |
+--------+-------+------------+----------+------------+
| A      |   200 | 2018-04-21 | A1       |          1 |
| B      |   500 | 2018-04-20 | A1       |          3 |
+--------+-------+------------+----------+------------+
2 rows in set (0.00 sec)

Mucho ojo, si hubiera más registros con la misma fecha máxima te regresaría MAS DE UN REGISTRO para cada código... si solo quieres mostrar uno ahí tendrías que hacer las cosas distintas.

Haz la prueba y nos comentas.

Saludos
Leo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
2
Comentar
sin imagen de perfil
Val: 37
Ha mantenido su posición en SQL (en relación al último mes)
Gráfica de SQL

Como obtener varios valores superiores en una tabla?

Publicado por Jorge (19 intervenciones) el 12/07/2018 16:47:52
Saludos!

A ver he hecho lo siguiente
Como pueden existir Codigos con fechas iguales o Registros iguales (CodInterno no, porque es un número único,)

Podrían haber varios resultados para MAXFecha y MAXRegistro entonces hice lo siguiente:

Usando el ejemplo que me diste hice lo mismo pero anidando según el criterio de orden que necesitaba
1ro Fecha, 2do Registro y 3ro CodInterno

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Select T6.*
from Tabla1 T6
Inner join
      /* Obtengo los resultados con el CodInterno mayor que aparezca en la subconsulta de MAX(Registro) */
      (Select T4.Codigo, max(T4.CodInterno) MaxCodInterno
       from Tabla1 T4
       Inner join
             /* Obtengo los resultados con el Registro mayor que aparezca en la subconsulta de MAX(Fecha) */
             (Select T2.Codigo, max(T2.Registro) MaxRegistro
              from Tabla1 T2
              inner join
                    /* Obtengo los resultados con la fecha mayor */
                    (select Codigo, max(fecha) MaxFecha
                     from Tabla1
                     group by Codigo) T1
 
              ON T2.Codigo = T1.Codigo
              AND T2.Fecha = T1.MaxFecha
              group by T2.Codigo) T3
 
       ON  T4.Codigo = T3.Codigo
       AND T4.Registro = T3.MaxRegistro
       group by T4.Codigo) T5
 
ON T6.Codigo = T5.Codigo
AND T6.CodInterno = T5.MaxCodInterno
Order By T6.Codigo

Ahora que sea un código óptimo o que sea la forma correcta de hacerlo eso si no se,
pero es lo que se me va ocurriendo
(Aunque hice la prueba con 80,000 registros aprox. y se demoró menos de 1 segundo)

Igual haré la prueba con varios casos de uso simples a ver si de verdad me bota lo que quiero :o

Gracias!
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar