Foros del Web » Programación para mayores de 30 ;) » Bases de Datos General » SQL Server »

Consulta recursiva

Estas en el tema de Consulta recursiva en el foro de SQL Server en Foros del Web. Hola Estimados, Hace tiempo no entraba por acá, pero ahora tengo una duda digna de ustedes. He estado trabajando en SQL 2008 con tablas recursivas ...
  #1 (permalink)  
Antiguo 04/09/2013, 09:57
 
Fecha de Ingreso: septiembre-2013
Mensajes: 9
Antigüedad: 11 años, 3 meses
Puntos: 0
Pregunta Consulta recursiva

Hola Estimados,

Hace tiempo no entraba por acá, pero ahora tengo una duda digna de ustedes. He estado trabajando en SQL 2008 con tablas recursivas para generar la estructura organizacional de la empresa. Algo así

tbl_estructura_organizativa
est_org_id
est_org_id_padre
niv_org_nivel
est_org_nombre

Donde est_org_id_padre referencia a est_org_id y niv_org_nivel indica el nivel de profundidad desde 1 hasta n. En este caso la estructura que tengo es Franquiciado, Razon Social, Local, en donde un franquiciado tiene n razones sociales y una razon social tiene n locales. Entonces:
- Franquiciado => niv_org_nivel = 1 y est_org_id_padre = NULL
- Razon social => niv_org_nivel = 2 y est_org_id_padre = id algun franquiciado
- Local => niv_org_nivel = 3 y est_org_id_padre = id alguna razon social

Ahora bien, tengo también una tabla de personas que se relaciona a est_org_id

tbl_persona
per_id
est_org_id
per_nombre

Cada persona se relaciona a un local, no a una razon social o franquiciado directamente sino a un local en especifico. Eso sí, hay que considerar que los otros casos igual podrían darse aunque por ahora no ocurre.

El tema es que necesito saber cuánta gente está asociado a cada franquiciado. En lo práctico esto implica sumar todas las personas que estén asociados a cada razon social y/o local que corresponda al franquiciado.

La verdad es que anteriormente no había trabajado con tablas recursivas, pero me lancé no más pensando "en el camino se arregla la carga" y si bien he logrado un par de soluciones la verdad no están muy lindas y quiero buscar una más óptima. Y humildemente pido su ayuda al respecto

Por ahora he estado jugando un poco con las CTE, pero me trae la estructura completa con todas las razones sociales y los locales de cada franquiciado, eso está OK, sirve en algunos casos, pero para éste en específico necesito el dato consolidado a nivel de franquiciado y no el detalle a nivel de local. ¿Se les ocurre alguna idea?. De antemano mil gracias . Les dejo el código SQL con el que he estado jugando

Código:
WITH Estructura (niv_org_nombre, est_org_id, est_org_nombre, niv_org_nivel) AS (
	SELECT n.niv_org_nombre, eo.est_org_id, eo.est_org_nombre, eo.niv_org_nivel
	FROM tbl_estructura_organizativa eo 
	INNER JOIN tbl_nivel_organizativo n ON n.niv_org_nivel=eo.niv_org_nivel
	WHERE eo.est_org_id_padre IS NULL
	AND eo.niv_org_nivel=1
	UNION ALL
	
	SELECT n.niv_org_nombre, eo.est_org_id, eo.est_org_nombre, eo.niv_org_nivel
	FROM tbl_estructura_organizativa eo 
	INNER JOIN tbl_nivel_organizativo n ON n.niv_org_nivel=eo.niv_org_nivel
	INNER JOIN Estructura AS est ON est.est_org_id=eo.est_org_id_padre
)

SELECT e.est_org_id, e.est_org_nombre, e.niv_org_nivel, tmpInscritos.inscritos
FROM Estructura e 
LEFT JOIN (
	SELECT COUNT(DISTINCT p.per_id) as inscritos, est_org_id
	FROM tbl_persona p
	GROUP BY est_org_id
) tmpInscritos ON tmpInscritos.est_org_id=e.est_org_id
WHERE e.niv_org_nivel=1
GROUP BY e.est_org_id, e.est_org_nombre, e.niv_org_nivel, inscritos
ORDER BY e.niv_org_nivel ASC, e.est_org_nombre ASC;

Gracias a todos por el interés

Un abrazo,

Rodrigo
  #2 (permalink)  
Antiguo 04/09/2013, 10:15
Avatar de Libras
Colaborador
 
Fecha de Ingreso: agosto-2006
Ubicación: En la hermosa perla de occidente
Mensajes: 7.412
Antigüedad: 18 años, 4 meses
Puntos: 774
Respuesta: Consulta recursiva

recursividad con CTE, mmm prefiero la recursividad a nivel funcion :P podrias poner un ejemplo de tus datos?
__________________
What does an execution plan say to t-sql query? Go f**k yourself, if you are not happy with me
  #3 (permalink)  
Antiguo 04/09/2013, 10:43
 
Fecha de Ingreso: septiembre-2013
Mensajes: 9
Antigüedad: 11 años, 3 meses
Puntos: 0
Respuesta: Consulta recursiva

Código SQL:
Ver original
  1. est_org_id  est_org_id_padre    niv_org_nivel   est_org_nombre
  2. 1            NULL               1               Franquiciado 1
  3. 2            1                  2               Razon Social 1
  4. 3            1                  2               Razon Social 2
  5. 4            NULL               1               Franquiciado 2
  6. 5            2                  2               LOCAL 1
  7. 6            2                  2               LOCAL 2
  8. 7            2                  3               LOCAL 3

Acá los locales 1 y 2 correspondiente a la razon social 1 que a su vez corresponde al franquiciado 1.

El local 3 corresponde a la razon social 2 del franquiciado 1 también

El franquiciado 2 no tiene razones sociales o locales

Las personas en este caso irían asociados a los ID 5, 6 y 7

Con respecto a si hacerlo por CTE o por funciones, la verdad no estoy cerrado a ninguna opción. Por ahora estoy trabajando con funciones y evaluando el tema de las CTE, pero me gustaría tener más opiniones

Muchas gracias de nuevo
  #4 (permalink)  
Antiguo 04/09/2013, 10:56
 
Fecha de Ingreso: septiembre-2013
Mensajes: 9
Antigüedad: 11 años, 3 meses
Puntos: 0
Respuesta: Consulta recursiva

Bueno, agrego un dato. Ahora por ejemplo tengo una función a la que paso como parámetro el id de la estructura y me devuelve todo lo que tenga esa estructura, el problema es cómo pasar el parámetro a la función en una misma consulta.

Lo que se puede hacer es crear un cursor que obtenga las estructuras y luego pasar id como parámetro

Código SQL:
Ver original
  1. SELECT *
  2. FROM tbl_persona p
  3. INNER JOIN udf_recorreEstructura(@id_estructura) fn ON fn.est_org_id=p.est_org_id

Y resulta, pero es una solución bien fea. Yo preferiría hacerlo todo en una misma consulta, pero es ahí donde estoy bastante enredado

Gracias de nuevo por la ayuda
  #5 (permalink)  
Antiguo 04/09/2013, 11:06
Avatar de Libras
Colaborador
 
Fecha de Ingreso: agosto-2006
Ubicación: En la hermosa perla de occidente
Mensajes: 7.412
Antigüedad: 18 años, 4 meses
Puntos: 774
Respuesta: Consulta recursiva

Cita:
Iniciado por rvaldenegro Ver Mensaje
Código SQL:
Ver original
  1. est_org_id  est_org_id_padre    niv_org_nivel   est_org_nombre
  2. 1            NULL               1               Franquiciado 1
  3. 2            1                  2               Razon Social 1
  4. 3            1                  2               Razon Social 2
  5. 4            NULL               1               Franquiciado 2
  6. 5            2                  2               LOCAL 1
  7. 6            2                  2               LOCAL 2
  8. 7            2                  3               LOCAL 3

Acá los locales 1 y 2 correspondiente a la razon social 1 que a su vez corresponde al franquiciado 1.

El local 3 corresponde a la razon social 2 del franquiciado 1 también

El franquiciado 2 no tiene razones sociales o locales

Las personas en este caso irían asociados a los ID 5, 6 y 7

Con respecto a si hacerlo por CTE o por funciones, la verdad no estoy cerrado a ninguna opción. Por ahora estoy trabajando con funciones y evaluando el tema de las CTE, pero me gustaría tener más opiniones

Muchas gracias de nuevo
Podrias explicar un poco mejor la estrucutra de tu tabla? yo por lo general una estructura de padres la manejo de este modo

id Id_padre nivel
1 NUll 0
2 1 1
3 1 1
4 3 2

saludos!
__________________
What does an execution plan say to t-sql query? Go f**k yourself, if you are not happy with me
  #6 (permalink)  
Antiguo 04/09/2013, 11:11
Avatar de iislas
Colaborador
 
Fecha de Ingreso: julio-2007
Ubicación: Mexico, D.F.
Mensajes: 6.482
Antigüedad: 17 años, 5 meses
Puntos: 180
Respuesta: Consulta recursiva

Libras: conectate a skype
__________________
MCTS Isaias Islas
  #7 (permalink)  
Antiguo 04/09/2013, 12:15
 
Fecha de Ingreso: septiembre-2013
Mensajes: 9
Antigüedad: 11 años, 3 meses
Puntos: 0
Respuesta: Consulta recursiva

Cita:
Iniciado por Libras Ver Mensaje
Podrias explicar un poco mejor la estrucutra de tu tabla? yo por lo general una estructura de padres la manejo de este modo

id Id_padre nivel
1 NUll 0
2 1 1
3 1 1
4 3 2

saludos!
Es exactamente lo mismo pero con otros nombres.

Gracias,

R
  #8 (permalink)  
Antiguo 10/09/2013, 09:25
 
Fecha de Ingreso: septiembre-2013
Mensajes: 9
Antigüedad: 11 años, 3 meses
Puntos: 0
Respuesta: Consulta recursiva

Holas,

Después de investigar un rato encontré una solución, requiere de dos pasos: 1 función recursiva para obtener las estructuras y una consulta CTE para obtener la cantidad de personas.

Queda así:

Código SQL:
Ver original
  1. ALTER FUNCTION [dbo].[udf_recorreEstructura](
  2.     @pm_est_org_id INT
  3. )
  4. RETURNS @tmpEstOrg TABLE (
  5.     est_org_id INTEGER
  6.     , est_org_id_padre INTEGER NULL
  7.     , niv_org_nivel VARCHAR(150)
  8.     , niv_org_nombre VARCHAR(100)
  9.     , reg_id INTEGER NULL
  10.     , ciu_id INTEGER NULL
  11.     , com_id INTEGER NULL
  12.     , est_org_nombre VARCHAR(100)
  13.     , est_org_descripcion VARCHAR(200) NULL
  14.     , est_org_fec_creacion datetime NULL
  15.     , est_org_activa bit NULL
  16. )  
  17. AS
  18. BEGIN
  19.     --primero verificamos que venga un entero valido
  20.     IF (isnumeric(@pm_est_org_id)=1 AND @pm_est_org_id>0)
  21.     BEGIN
  22.         DECLARE @id_estructura INTEGER;
  23.         SET @id_estructura = CONVERT(INTEGER, @pm_est_org_id);
  24.        
  25.         IF (@id_estructura>0)
  26.         BEGIN
  27.             INSERT INTO @tmpEstOrg (
  28.                 est_org_id, est_org_id_padre, niv_org_nivel, niv_org_nombre, reg_id, ciu_id, com_id
  29.                 , est_org_nombre, est_org_descripcion, est_org_fec_creacion, est_org_activa
  30.             ) SELECT eo.est_org_id, eo.est_org_id_padre, eo.niv_org_nivel, niv.niv_org_nombre
  31.             , eo.reg_id, eo.ciu_id, eo.com_id
  32.             , eo.est_org_nombre, eo.est_org_descripcion, eo.est_org_fec_creacion, eo.est_org_activa
  33.             FROM tbl_estructura_organizativa eo
  34.             LEFT JOIN tbl_nivel_organizativo niv ON niv.niv_org_nivel=eo.niv_org_nivel
  35.             WHERE est_org_id_padre=@id_estructura;
  36.            
  37.             INSERT INTO @tmpEstOrg (
  38.                 est_org_id, est_org_id_padre, niv_org_nivel, niv_org_nombre, reg_id, ciu_id, com_id
  39.                 , est_org_nombre, est_org_descripcion, est_org_fec_creacion, est_org_activa
  40.             ) SELECT f.est_org_id, f.est_org_id_padre, f.niv_org_nivel, f.niv_org_nombre
  41.             , f.reg_id, f.ciu_id, f.com_id
  42.             , f.est_org_nombre, f.est_org_descripcion, f.est_org_fec_creacion, f.est_org_activa
  43.             FROM @tmpEstOrg t
  44.             CROSS APPLY dbo.udf_recorreEstructura(t.est_org_id) f
  45.         END
  46.     END
  47.     RETURN
  48. END


Y luego la consulta CTE

Código SQL:
Ver original
  1. WITH
  2. cteEstructura (
  3.     est_org_id, est_org_nombre
  4. ) AS (
  5.     SELECT est_org_id, est_org_nombre
  6.     FROM tbl_estructura_organizativa
  7.     WHERE est_org_id_padre=0
  8.     OR est_org_id_padre IS NULL
  9. ),
  10. cteInscritos (
  11.     est_org_id, inscritos
  12. ) AS (
  13.     SELECT e.est_org_id, COUNT(p.rut_persona) AS total
  14.     FROM cteEstructura e
  15.     CROSS APPLY dbo.udf_recorreEstructura(e.est_org_id) f
  16.     INNER JOIN tbl_persona p ON p.est_org_id=f.est_org_id
  17.     GROUP BY e.est_org_id
  18. )
  19. SELECT e.est_org_nombre, SUM(i.inscritos) AS inscritos
  20. FROM cteEstructura e
  21. INNER JOIN cteInscritos i ON i.est_org_id=e.est_org_id
  22. GROUP BY e.est_org_nombre
  23. ORDER BY inscritos DESC

Por ahora es la solución que he encontrado y funciona bien, aún creo que existen un par de detalles que pulir y estaré trabajando en ellos.

Agradezco la ayuda al respecto.

Saludos
  #9 (permalink)  
Antiguo 10/09/2013, 09:38
Avatar de Libras
Colaborador
 
Fecha de Ingreso: agosto-2006
Ubicación: En la hermosa perla de occidente
Mensajes: 7.412
Antigüedad: 18 años, 4 meses
Puntos: 774
Respuesta: Consulta recursiva

to much code, but if works is fine :P

__________________
What does an execution plan say to t-sql query? Go f**k yourself, if you are not happy with me
  #10 (permalink)  
Antiguo 10/09/2013, 09:46
 
Fecha de Ingreso: septiembre-2013
Mensajes: 9
Antigüedad: 11 años, 3 meses
Puntos: 0
Respuesta: Consulta recursiva

bueno, si hubiera una versión resumida mejor, de momento no se me ocurre
  #11 (permalink)  
Antiguo 10/09/2013, 10:00
Avatar de Libras
Colaborador
 
Fecha de Ingreso: agosto-2006
Ubicación: En la hermosa perla de occidente
Mensajes: 7.412
Antigüedad: 18 años, 4 meses
Puntos: 774
Respuesta: Consulta recursiva

esque podrias hacerlo en una sola funcion metiendo un ciclo dentro de la misma lo que tendrias que hacer es obtener los hijos del registro que mandas como parametro y analizar cada uno de estos elementos si alguno de ellos tiene hijos entonces llamas a la funcion recursiva :P es lo que estas haciendo pero con una sola funcion
__________________
What does an execution plan say to t-sql query? Go f**k yourself, if you are not happy with me

Etiquetas: recursiva, select, sql, tabla
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 02:06.