La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Tablas y Funciones de SQL Server para Implementar una Jerarquía sin Límite de Niveles Leonel Morales Díaz Ingeniería Simple

Presentaciones similares


Presentación del tema: "Tablas y Funciones de SQL Server para Implementar una Jerarquía sin Límite de Niveles Leonel Morales Díaz Ingeniería Simple"— Transcripción de la presentación:

1 Tablas y Funciones de SQL Server para Implementar una Jerarquía sin Límite de Niveles Leonel Morales Díaz Ingeniería Simple leonel@ingenieriasimple.com Copyright 2008 by Leonel Morales Díaz – Ingeniería Simple. Derechos reservados Disponible en: http://www.ingenieriasimple.com/TSQL

2 Jerarquías usuales Estructura tabla padre – tabla hijo –La llave primaria de la padre es llave foránea en la hija –Puede haber una tabla nieto Hasta una biznieto Padres Código Descripción Hijos Código CódigoPadre Descripción Nietos Código CódigoHijoPadre Descripción

3 Problemas en jerarquías Limitada a tres niveles –O a la cantidad de niveles establecida –Inflexibilidad: Nuevos niveles reales deben ser adaptados –La estructura es permanente y coercitiva Aunque un nivel ya no sea necesario Dificultad de consultas –Se trata de relacionar tres o más tablas

4 Jerarquías de una sola tabla Estructura registro hijo – registro padre –La llave primaria es llave foránea de la misma tabla Si no hay padre la llave foránea es nula –Tabla con relación a sí misma Datos Código CódigoPadre Descripción

5 Ventajas jerarquía unitabla Ilimitados niveles –Se ajusta a las necesidades reales Consultas más sencillas Estructura más simple –Llega a conocerse muy bien Bastante flexible

6 Desventajas El nivel del registro no se conoce inmediatamente –En la jerarquía tradicional se conoce el nivel con solo saber a qué tabla pertenece –Se necesita agregar campos para esto

7 Jerarquía contable Usualmente por posiciones en una cadena –#.##.###.#### –Cuenta, subcuenta, sub-subcuenta, cuenta de detalle, etc. Puede ser una sola tabla –Con referencia a sí misma La cantidad de niveles está pre-establecida No hay necesidad de campo con cuenta padre Usualmente se llama Nomenclatura Contable

8 Ejemplo jerarquía contable En el código está implícito el código del padre Puede ser necesario poner validaciones para evitar que se inserte un código sin padre –Los códigos de longitud 1 no tienen padre Una sola tabla CódigoCuenta 1Activo 2Pasivo 3Capital 4Gastos 5Ingresos 1.1Circulante 1.2Fijo 1.3Diferido 2.1Circulante 2.2Fijo 2.3Diferido 3.1Acciones al portador 3.2Acciones preferentes 4.1Fijos 4.2Variables 5.1Fijos 5.2Variables 1.1.1Caja 1.1.2Bancos

9 Nomenclatura Implementación –Puede hacerse mediante constraints de tipo Check Y una función para encontrar el código padre Si la función devuelve Null no se acepta Nomenclatura Código Cuenta CREATE TABLE Nomenclatura( Código nVarChar(13) NOT NULL CONSTRAINT Código_Nomenclatura Check ( (Código Like '[1-9]' Or Código Like '[1-9].[0-9][0-9]' Or Código Like '[1-9].[0-9][0-9].[0-9][0-9][0-9]' Or Código Like '[1-9].[0-9][0-9].[0-9][0-9][0-9].[0-9][0-9][0-9][0-9]') And (len(Código)=1 Or Not dbo.CuentaPadre(Código) Is Null)), Cuenta nVarChar(30) NULL, Constraint PK_Nomenclatura Primary Key Clustered ( Código ASC ) )

10 Función para chequeo CuentaPadre(@Código) –Encuentra la cuenta padre de @Código –Si no hay devuelve Null CREATE FUNCTION CuentaPadre ( @Código nVarChar(13) ) RETURNS nVarChar(13) AS BEGIN DECLARE @Resu nVarChar(13) Set @Resu = Null If CharIndex('.',@Código) > 0 Begin Declare @PosiblePadre nVarChar(13) Set @PosiblePadre = RTrim(@Código) While Right(@PosiblePadre,1) <> '.' Set @PosiblePadre = Left(@PosiblePadre,Len(@PosiblePadre)-1) Select @Resu = Código From Nomenclatura Where Código = @PosiblePadre End RETURN @Resu END

11 Padre y nivel Se pueden implementar con campos calculados Padre –El valor devuelto por CuentaPadre Nivel –El número de puntos más 1 –Se puede hacer con una función que los cuente o aprovechando la función Like

12 Tabla con padre y nivel Nomenclatura Código Cuenta Padre Nivel CREATE TABLE Nomenclatura( Código nVarChar(13) NOT NULL CONSTRAINT Código_Nomenclatura Check ( (Código Like '[1-9]' Or Código Like '[1-9].[0-9][0-9]' Or Código Like '[1-9].[0-9][0-9].[0-9][0-9][0-9]' Or Código Like '[1-9].[0-9][0-9].[0-9][0-9][0-9].[0-9][0-9][0-9][0-9]') And (len(Código)=1 Or Not dbo.CuentaPadre(Código) Is Null)), Cuenta nVarChar(30) NULL, Padre As dbo.CuentaPadre(Código), Nivel As Case When Código Like '%.%.%.%' Then 4 When Código Like '%.%.%' Then 3 When Código Like '%.%' Then 2 Else 1 End, Constraint PK_Nomenclatura Primary Key Clustered ( Código ASC ) )

13 Datos de tabla Nomenclatura Select * From Nomenclatura Código Cuenta Padre Nivel ------------- ------------------------------ ------------- ----------- 1 Activo NULL 1 1.01 Circulante 1 2 1.01.001 Caja 1.01 3 1.01.002 Bancos 1.01 3 1.01.002.0001 Banco Industrial 1.01.002 4 1.01.002.0002 Banco Continental 1.01.002 4 1.01.002.0003 Banco Internacional 1.01.002 4 1.02 Fijo 1 2 1.03 Diferido 1 2 2 Pasivo NULL 1 2.01 Circulante 2 2 2.02 Fijo 2 2 2.03 Diferido 2 2 3 Capital NULL 1 3.01 Acciones al portador 3 2 3.02 Acciones preferentes 3 2 4 Gastos NULL 1 4.01 Fijos 4 2 4.02 Variables 4 2 5 Ingresos NULL 1 5.01 Fijos 5 2 5.02 Variables 5 2 (22 row(s) affected)

14 Otros tipos de jerarquía Por ruta o path –Similar a la de directorios de windows –Se tiene un nodo raíz y un separador C:, D:, etc., son raíces \ es el separador –Todos los nodos de un mismo nivel tienen la misma cantidad de separadores en la ruta –Todos los hijos de un mismo nodo comparten el mismo prefijo Generalización: jerarquía por prefijo –Puede o no existir separador En cualquier caso se usa solo una tabla

15 Planteamiento Partiendo de una jerarquía de una sola tabla construir las consultas para: –Obtener la lista de padres Registros sin padre –Obtener la lista de registros en el nivel n –Obtener la lista de registros descendientes del registro R –Obtener la lista de registros que descienden del registro P y están en el nivel m

16 Tabla básica Solo tres campos –Código –CódigoPadre –Descripción El resto serán calculados –Padre –Nivel –Ruta Datos Código CódigoPadre Descripción

17 Creación de la tabla básica La tabla permite almacenar cualquier jerarquía En este ejemplo se usará para países y provincias geográficas (departamentos), municipios, etc. CREATE TABLE Datos( Código Int NOT NULL, CódigoPadre Int NULL Constraint FK_Datos_CódigoPadre Foreign Key References Datos ( Código ), Descripción nVarChar(Max), Constraint PK_Datos Primary Key Clustered ( Código ASC ) ) Datos Código CódigoPadre Descripción

18 Registros para pruebas Select * From Datos Código CódigoPadre Descripción ----------- ----------- ----------------------- 1 NULL Guatemala 2 NULL El Salvador 3 NULL Honduras 4 NULL Nicaragua 5 NULL Costa Rica 6 NULL Belice 7 NULL Panamá 8 1 Guatemala 9 1 Sacatepequez 10 1 Chimaltenango 11 1 Sololá 12 1 Totonicapán 13 1 Huehuetenango 14 1 Quetzaltenango 15 1 San Marcos 16 1 Retalhuleu 17 1 Suchitepequez 18 1 Escuintla 19 1 Santa Rosa 20 1 Jutiapa 21 1 Jalapa 22 1 Zacapa 23 1 Izabal 24 1 Baja Verapaz 25 1 Alta Verapaz 26 1 Quiché 27 1 Petén 28 1 El Progreso 29 8 Ciudad de Guatemala 30 8 Mixco 31 8 Villa Nueva 32 8 Jocotenango 33 9 San Juan Sacatepequez 34 9 San Raymundo 35 9 Antigua Guatemala 36 8 Amatitlán 37 11 Atitlán 38 11 San Pedro La Laguna 39 13 Chiantla 40 39 Los Regadillos 41 13 Huehuetenango 42 41 El Terrero 43 41 El Cambote (43 row(s) affected)

19 Lista de padres Padres: –Registros sin padre –CódigoPadre Is Null Select * From Datos Where CódigoPadre Is Null Código CódigoPadre Descripción ----------- ----------- ------------------ 1 NULL Guatemala 2 NULL El Salvador 3 NULL Honduras 4 NULL Nicaragua 5 NULL Costa Rica 6 NULL Belice 7 NULL Panamá (7 row(s) affected)

20 Lista de registros en nivel n Se necesita una función que calcule el nivel Puede ser recursiva Create Function CalculaNivelDato ( @Código As Int ) Returns Int As Begin Declare @CódigoPadre Int Declare @Nivel Int Select @CódigoPadre = CódigoPadre From Datos Where Código = @Código If (@CódigoPadre) Is Null Set @Nivel = 1 Else Set @Nivel = dbo.CalculaNivelDato(@CódigoPadre) + 1 Return @Nivel End Select * From Datos Where dbo.CalculaNivelDato(Código) = 3 Código CódigoPadre Descripción ----------- ----------- --------------------- 29 8 Ciudad de Guatemala 30 8 Mixco 31 8 Villa Nueva 32 8 Jocotenango 33 9 San Juan Sacatepequez 34 9 San Raymundo 35 9 Antigua Guatemala 36 8 Amatitlán 37 11 Atitlán 38 11 San Pedro La Laguna 39 13 Chiantla 41 13 Huehuetenango (12 row(s) affected)

21 Nivel como campo calculado Se puede incorporar el nivel como campo calculado –Usando la función CalculaNivelDato CREATE TABLE Datos( Código Int NOT NULL, CódigoPadre Int NULL Constraint FK_Datos_CódigoPadre Foreign Key References Datos ( Código ), Descripción nVarChar(Max), Nivel As dbo.CalculaNivelDato(Código), Constraint PK_Datos Primary Key Clustered ( Código ASC ) ) Select * From Datos Where Nivel = 3 or Nivel = 4 Código CódigoPadre Descripción Nivel ----------- ----------- ---------------------- ------ 29 8 Ciudad de Guatemala 3 30 8 Mixco 3 31 8 Villa Nueva 3 32 8 Jocotenango 3 33 9 San Juan Sacatepequez 3 34 9 San Raymundo 3 35 9 Antigua Guatemala 3 36 8 Amatitlán 3 37 11 Atitlán 3 38 11 San Pedro La Laguna 3 39 13 Chiantla 3 40 39 Los Regadillos 4 41 13 Huehuetenango 3 42 41 El Terrero 4 43 41 El Cambote 4 (15 row(s) affected)

22 Lista de descendientes de R Prerrequisito: –Función que construye el path hacía la raíz También se puede hacer recursiva –Usa delimitadores: > antes y = después Para evitar el código 30 se confunda con el 3030 por ejemplo Facilita las búsquedas –Ejemplo: path de 30: >1=>8=>30=

23 Función de ruta Create Function ComponePathDato ( @Código As Int ) Returns nVarChar(Max) As Begin Declare @CódigoPadre Int Declare @Path nVarChar(Max) Set @Path = '>' + Convert(nVarChar(Max),@Código) + '=' Select @CódigoPadre = CódigoPadre From Datos Where Código = @Código If Not (@CódigoPadre) Is Null Set @Path = dbo.ComponePathDato(@CódigoPadre) + @Path Return @Path End Select Código, dbo.ComponePathDato(Código) From Datos Where Nivel = 3 or Nivel = 4 Código ----------- ------------------- 29 >1=>8=>29= 30 >1=>8=>30= 31 >1=>8=>31= 32 >1=>8=>32= 33 >1=>9=>33= 34 >1=>9=>34= 35 >1=>9=>35= 36 >1=>8=>36= 37 >1=>11=>37= 38 >1=>11=>38= 39 >1=>13=>39= 40 >1=>13=>39=>40= 41 >1=>13=>41= 42 >1=>13=>41=>42= 43 >1=>13=>41=>43= (15 row(s) affected)

24 Ruta como campo calculado Similar al caso de Nivel CREATE TABLE Datos( Código Int NOT NULL, CódigoPadre Int NULL Constraint FK_Datos_CódigoPadre Foreign Key References Datos ( Código ), Descripción nVarChar(Max), Nivel As dbo.CalculaNivelDato(Código), Ruta As dbo.ComponePathDato(Código), Constraint PK_Datos Primary Key Clustered ( Código ASC ) ) Select Código, Nivel, Ruta From Datos Where Nivel = 4 Código Nivel Ruta ----------- ----------- ---------------- 40 4 >1=>13=>39=>40= 42 4 >1=>13=>41=>42= 43 4 >1=>13=>41=>43= (3 row(s) affected)

25 ¡Ahora sí! Descendientes de R Descendientes de R tienen la ruta de R en su ruta Declare @Ruta nVarChar(Max) Select @Ruta = Ruta From Datos Where Código = 13 Select * From Datos Where Ruta Like @Ruta + '%' And Ruta <> @Ruta Código CódigoPadre Descripción Nivel Ruta ----------- ----------- --------------- ----------- ---------------- 39 13 Chiantla 3 >1=>13=>39= 40 39 Los Regadillos 4 >1=>13=>39=>40= 41 13 Huehuetenango 3 >1=>13=>41= 42 41 El Terrero 4 >1=>13=>41=>42= 43 41 El Cambote 4 >1=>13=>41=>43= (5 row(s) affected)

26 Descendientes de P en nivel m Igual que el anterior –Pero con condición sobre el nivel Declare @Ruta nVarChar(Max) Select @Ruta = Ruta From Datos Where Código = 13 Select * From Datos Where Ruta Like @Ruta + '%' And Ruta <> @Ruta And Nivel = 3 Código CódigoPadre Descripción Nivel Ruta ----------- ----------- ------------- ----------- ------------ 39 13 Chiantla 3 >1=>13=>39= 41 13 Huehuetenango 3 >1=>13=>41= (2 row(s) affected) Select * From Datos Where Ruta Like @Ruta + '%' And Ruta <> @Ruta And Nivel = 4 Código CódigoPadre Descripción Nivel Ruta ----------- ----------- --------------- ----------- ---------------- 40 39 Los Regadillos 4 >1=>13=>39=>40= 42 41 El Terrero 4 >1=>13=>41=>42= 43 41 El Cambote 4 >1=>13=>41=>43= (3 row(s) affected)

27 Variaciones de las funciones Calcular el nivel a partir de la ruta –El nivel es el número de > o = en la ruta Transformar las funciones a formas no recursivas Usar vistas para evitar los campos calculados Poner el código en Identity generado automáticamente

28 Formas no recursivas Función de cálculo de nivel Create Function CalculaNivelDato ( @Código As Int ) Returns Int As Begin Declare @CódigoPadre Int Select @CódigoPadre = CódigoPadre From Datos Where Código = @Código Declare @Nivel Int Set @Nivel = 1 While Not @CódigoPadre Is Null Begin Set @Nivel = @Nivel + 1 Select @CódigoPadre = CódigoPadre From Datos Where Código = @CódigoPadre End Return @Nivel End

29 Formas no recursivas Función de composición de rutas Create Function ComponePathDato ( @Código As Int ) Returns nVarChar(Max) As Begin Declare @CódigoPadre Int Declare @Path nVarChar(Max) Select @CódigoPadre = CódigoPadre, @Path = '>' + Convert(nVarChar(Max),Código) + '=' From Datos Where Código = @Código While Not @CódigoPadre Is Null Select @CódigoPadre = CódigoPadre, @Path = '>' + Convert(nVarChar(Max),Código) + '=' + @Path From Datos Where Código = @CódigoPadre Return @Path End


Descargar ppt "Tablas y Funciones de SQL Server para Implementar una Jerarquía sin Límite de Niveles Leonel Morales Díaz Ingeniería Simple"

Presentaciones similares


Anuncios Google