Ir al contenido


Foto

obtener el ultimo registro de un maestro/ detalle en un query


  • Por favor identifícate para responder
5 respuestas en este tema

#1 razadi

razadi

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 681 mensajes
  • LocationMéxico D.F.

Escrito 24 enero 2017 - 11:21

Buenos días amigos y compañeros, quiero consultarles lo siguiente:

 

tengo dos tablas

 

tbl_maestro(id_maestro,...)

tbl_detalle(id_maestro,cons,...)

 

si yo genero un query así obtengo todos los registros del detalle...


sql
  1. SELECT
  2. *
  3. FROM TBL_MAESTRO M
  4. INNER JOIN DETALLE D ON (M.ID_MAESTRO=D.ID_MAESTRO)

Pero yo sólo quiero obtener el último registro del detalle en esta consulta y NO todos.

 

lo eh hecho muy rustico de la siguiente manera pero ya no es servible por que ya hay muchos registros en el detalle y tarda bastante


sql
  1. SELECT
  2. *
  3. FROM TBL_MAESTRO M
  4. INNER JOIN DETALLE D ON (D.ID_MAESTRO=M.ID_MAESTRO) AND (D.CONS = (SELECT MAX(CONS) FROM TBL_DETALLE WHERE ID_MAESTRO=D.ID_MAESTRO))

Si alguien tiene una sugerencia, se la agradecería.

 

saludos y gracias


  • 0

#2 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 24 enero 2017 - 03:38

Si sólo deseas obtener el último debería ser suficiente con que hagas un:


sql
  1. SELECT FIRST 1
  2. FROM ...
  3. ORDER BY CAMPO DESC

Esto va a funcionar mientras el campo por el cual se va a ordenar de forma descendente sea coincidente con el criterio correlativo/incremental y en caracter de "orden". Es decir que si en realidad puede darse el caso en que el valor "máximo" no necesariamente implique que sea el último registro, esta forma no funciona.

Si tienes garantías de que los valores de CONS van en orden, ordenarlos de forma descendente hará que el máximo esté en primer lugar. Luego con FIRST 1 se condiciona a que la consulta se quede con el 1er registro del conjunto de datos.

 

Para acelerar la operatoria sería conveniente que sobre el/los campo/s que intervienen en el criterio WHERE y ORDER BY crees un índice. Lo más probable es que no tengas índices para esas tablas, o bien, si los tienes, no están siendo seleccionados y usados debido a que el plan de ejecución los descarta por no aplicarse a los campos de interés. En este ejemplo, yo sugeriría que crees un indice descendiente sobre campo CONS.

 

Saludos,


  • 0

#3 razadi

razadi

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 681 mensajes
  • LocationMéxico D.F.

Escrito 24 enero 2017 - 03:50

Si sólo deseas obtener el último debería ser suficiente con que hagas un:


sql
  1. SELECT FIRST 1
  2. FROM ...
  3. ORDER BY CAMPO DESC

Esto va a funcionar mientras el campo por el cual se va a ordenar de forma descendente sea coincidente con el criterio correlativo/incremental y en caracter de "orden". Es decir que si en realidad puede darse el caso en que el valor "máximo" no necesariamente implique que sea el último registro, esta forma no funciona.

Si tienes garantías de que los valores de CONS van en orden, ordenarlos de forma descendente hará que el máximo esté en primer lugar. Luego con FIRST 1 se condiciona a que la consulta se quede con el 1er registro del conjunto de datos.

 

Para acelerar la operatoria sería conveniente que sobre el/los campo/s que intervienen en el criterio WHERE y ORDER BY crees un índice. Lo más probable es que no tengas índices para esas tablas, o bien, si los tienes, no están siendo seleccionados y usados debido a que el plan de ejecución los descarta por no aplicarse a los campos de interés. En este ejemplo, yo sugeriría que crees un indice descendiente sobre campo CONS.

 

Saludos,

 

Gracias amigo, justo acabo de encontrar hacerlo de esa forma, no es lo que esperaba al 100% pero me funciona, saludos


  • 0

#4 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 24 enero 2017 - 04:03

Gracias amigo, justo acabo de encontrar hacerlo de esa forma, no es lo que esperaba al 100% pero me funciona, saludos

 

¿Porqué no al 100%?

¿Que es lo que le falta?

 

Si nos describes la estructura completa de estas 2 tablas y los índices que tienes en las mismas podremos ver que es lo que falla. Sería interesante saber el plan de ejecución que ejecuta firebird. Si usas IBExpert puedes ver el plan facilmente.

 

Saludos,


  • 0

#5 Marc

Marc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.484 mensajes
  • LocationMallorca

Escrito 25 enero 2017 - 01:29

La consulta original podría ejecutarse razonablemente bien con solo que tenga los índices adecuados, que en este caso va a tener que ser un índice múltiple (con más de un campo en el mismo índice).

 

Para que el motor pueda optmizar la subconsulta (que es el problema, ya que se vuelve a ejecutar para cada registro), va a necesitar un índice múltiple en la tabla DETALLE con los campos ID_MAESTRO, CONS.

 

create index IDX_DETALLE_ULTIMO on DETALLE (ID_MAESTRO, CONS);

 

Saludos.


  • 0

#6 Marc

Marc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.484 mensajes
  • LocationMallorca

Escrito 25 enero 2017 - 01:35

Adicionalmente también puedes rehacer tu consulta original usando CTE (Common Table Expressions) con lo que mejorarás su rendimiento (ya que el cuello de botella está en la subconsulta, la cual eliminamos).

 

https://firebird21.w...ble-expression/

 

Esto debería dar exactamente el mismo resultado:


php
  1. with ULTIMO_DETALLE as (
  2.   select ID_MAESTRO, max(CONS) as CONS
  3.   from DETALLE
  4. group by ID_MAESTRO
  5. )
  6.  
  7. select *
  8. from MAESTRO
  9.         left outer join ULTIMO_DETALLE on ULTIMO_DETALLE.ID_MAESTRO = MAESTRO.ID_MAESTRO
  10. left outer join DETALLE on DETALLE.CONS = ULTIMO_DETALLE.CONS

NOTA: Aunque esta consulta por si sola ya debería ser más rápida que la consulta original, si además también le añades el mismo índice múltiple en la Tabla DETALLE por los campos ID_MAESTRO, CONS, entonces Firebird aún podrá optimizar más su ejecución y devolver más rápido el resultado.

 

Saludos


  • 0




IP.Board spam blocked by CleanTalk.