none
Sacar los datos ordenados de una tabla. RRS feed

  • Pregunta

  • Buenos días.

    Tengo la siguiente tabla

    CREATE TABLE Grupo(
    GrupoID int]IDENTITY(1,1) NOT NULL,
    Nivel int NOT NULL,
    Denominacion nvarchar(50) NOT NULL,
    GrupoIDPadre int NULL,
    Orden int NULL,
     CONSTRAINT PK_Grupo PRIMARY KEY )

    GrupoIdPadre tiene una clave a GrupoId

    Quiero hacer una consulta en Sql Server para sacar una consulta ordenada por una nivel y por GrupoIDPadre y luego por Orden.

    Si tengo estos datos

    

    Con cursores lo consigo pero con un solo select no se si se puede.

    Gracias


    Marco


    • Editado MarcoGpex jueves, 26 de julio de 2018 7:50
    jueves, 26 de julio de 2018 7:47

Respuestas

  • Aqui tienes el codigo de acuerdo a lo que entendi.

    DECLARE @Grupo TABLE (
    GrupoID int ,
    Nivel int NOT NULL,
    Denominacion nvarchar(50) NOT NULL,
    GrupoIDPadre int NULL,
    Orden int NULL,
    PRIMARY KEY (GrupoID ASC) 
    );
    
    INSERT INTO @Grupo
    VALUES 
    	(1,1,'Solicitante',NULL,NULL),
    	(2,1,'Cursos',NULL,NULL),
    	(3,1,'Tablas Auxiliares',NULL,NULL),
    	(4,2,'Alumnos',1,1),
    	(5,2,'Entidad',1,2),
    	(6,2,'Colaborador',1,3),
    	(7,2,'Curso',2,1),
    	(8,2,'Edicion',2,2),
    	(9,2,'Pais',3,1),
    	(10,2,'Provincia',3,2),
    	(11,2,'Población',3,3);
    
    WITH R AS (
    SELECT
    	GrupoID,
        Nivel,
        Denominacion,
        GrupoIDPadre,
        ISNULL(Orden, 0) AS Orden,
    	CAST(
    	GrupoID AS varbinary(900)
    	) AS [Path]
    FROM
    	@Grupo
    WHERE
    	GrupoIDPadre IS NULL
    
    UNION ALL
    
    SELECT
    	C.GrupoID,
    	C.Nivel,
    	C.Denominacion,
    	C.GrupoIDPadre,
    	C.Orden,
    	CAST(
    	P.[Path] + CAST(ROW_NUMBER() OVER(PARTITION BY C.GrupoIDPadre, C.Nivel ORDER BY C.Orden) AS binary(4))
    	AS varbinary(900)
    	) AS [Path]
    FROM
    	R AS P
    	INNER JOIN
    	@Grupo AS C
    	ON C.GrupoIDPadre = P.GrupoID
    )
    SELECT
    	CONCAT(REPLICATE('|', (Nivel - 1) * 8) + CAST(GrupoID AS varchar(5)), ' - ', Denominacion) AS Grupo
    FROM
    	R
    ORDER BY
    	[Path];
    GO
    
    /*
    
    Grupo
    1 - Solicitante
    ||||||||4 - Alumnos
    ||||||||5 - Entidad
    ||||||||6 - Colaborador
    2 - Cursos
    ||||||||7 - Curso
    ||||||||8 - Edicion
    3 - Tablas Auxiliares
    ||||||||9 - Pais
    ||||||||10 - Provincia
    ||||||||11 - Población
    
    */

    La primera sentencia SELECT dentro de la CTE es el ancla y selecciona el nivel inicial (filas sin padres).  La segunda senetencia SELECT dentro de la CTE es la parte recursiva (referencia la misma CTE) y se encarga de seleccionar el proximo nivel por cada pasada hasta que no se retornen mas filas.

    En cuanto al orden de presentacion, la clave esta en formar una cadena binaria conformada por el grupo padre y nivel mas el orden que esta ocupa en el nivel indicado.

    La sentencia SELECT final hace referencia a la CTE y ordena la salida por el camino de la fila desde su grupo padre inicial.

    Puedes leer y aprender mas al respecto en los libros de Itzik Ben-Gan sobre T-SQL.

    T-SQL Fundamentals

    T-SQL Querying (Developer Reference)


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas

    • Editado HunchbackMVP viernes, 27 de julio de 2018 11:53
    • Marcado como respuesta MarcoGpex viernes, 27 de julio de 2018 12:02
    viernes, 27 de julio de 2018 11:50

Todas las respuestas

  • Sí, se puede hacer, pero es más complicado de lo que parece. Se necesita una CTE recursiva.

    Tienes la documentación de las CTE aquí:

    https://docs.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-2017

    Baja en esa página hasta el ejemplo "D". Ahí verás que hace algo parecido a lo que tú quieres, solo que usa una tabla de empleados que tienen un "jefe", y lista recuirsivamente cada jefe con sus subordinados. El campo "jefe" (ManagerId) es el equivalente de tu "GrupoIDPadre". A partir del ejemplo y con un poco de esfuerzo deberías ser capaz de construir una sentencia equivalente aplicable a tu caso.

    • Propuesto como respuesta HunchbackMVP jueves, 26 de julio de 2018 12:10
    jueves, 26 de julio de 2018 11:43
  • Gracias.

    Lo miraré y sino lo dejo con cursores.

    Saludos


    Marco

    jueves, 26 de julio de 2018 11:48
  • Postea la sentencia INSERT para la data de ejemplo junto con la definicion de la tabla y asi podremos tener algo con que probar nuestra sugerencia.

    No es necesario usar cursores para resolver este problema.


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas

    jueves, 26 de julio de 2018 12:10
  • Buenos días.

    Aquí van las sentencias.

    CREATE TABLE Grupo(
    GrupoID int ,
    Nivel int NOT NULL,
    Denominacion nvarchar(50) NOT NULL,
    GrupoIDPadre int NULL,
    Orden int NULL,
    CONSTRAINT PK_Grupo PRIMARY KEY CLUSTERED (GrupoID ASC) 
    )
    GO


    INSERT INTO Grupo
         VALUES (1,1,'Solicitante',NULL,NULL),
    (2,1,'Cursos',NULL,NULL),
    (3,1,'Tablas Auxiliares',NULL,NULL),
    (4,2,'Alumnos',1,1),
    (5,2,'Entidad',1,2),
    (6,2,'Colaborador',1,3),
    (7,2,'Curso',2,1),
    (8,2,'Edicion',2,2),
    (9,2,'Pais',3,1),
    (10,2,'Provincia',3,2),
    (11,2,'Población',3,3)

    Un saludo.


    Marco

    viernes, 27 de julio de 2018 5:44
  • Aqui tienes el codigo de acuerdo a lo que entendi.

    DECLARE @Grupo TABLE (
    GrupoID int ,
    Nivel int NOT NULL,
    Denominacion nvarchar(50) NOT NULL,
    GrupoIDPadre int NULL,
    Orden int NULL,
    PRIMARY KEY (GrupoID ASC) 
    );
    
    INSERT INTO @Grupo
    VALUES 
    	(1,1,'Solicitante',NULL,NULL),
    	(2,1,'Cursos',NULL,NULL),
    	(3,1,'Tablas Auxiliares',NULL,NULL),
    	(4,2,'Alumnos',1,1),
    	(5,2,'Entidad',1,2),
    	(6,2,'Colaborador',1,3),
    	(7,2,'Curso',2,1),
    	(8,2,'Edicion',2,2),
    	(9,2,'Pais',3,1),
    	(10,2,'Provincia',3,2),
    	(11,2,'Población',3,3);
    
    WITH R AS (
    SELECT
    	GrupoID,
        Nivel,
        Denominacion,
        GrupoIDPadre,
        ISNULL(Orden, 0) AS Orden,
    	CAST(
    	GrupoID AS varbinary(900)
    	) AS [Path]
    FROM
    	@Grupo
    WHERE
    	GrupoIDPadre IS NULL
    
    UNION ALL
    
    SELECT
    	C.GrupoID,
    	C.Nivel,
    	C.Denominacion,
    	C.GrupoIDPadre,
    	C.Orden,
    	CAST(
    	P.[Path] + CAST(ROW_NUMBER() OVER(PARTITION BY C.GrupoIDPadre, C.Nivel ORDER BY C.Orden) AS binary(4))
    	AS varbinary(900)
    	) AS [Path]
    FROM
    	R AS P
    	INNER JOIN
    	@Grupo AS C
    	ON C.GrupoIDPadre = P.GrupoID
    )
    SELECT
    	CONCAT(REPLICATE('|', (Nivel - 1) * 8) + CAST(GrupoID AS varchar(5)), ' - ', Denominacion) AS Grupo
    FROM
    	R
    ORDER BY
    	[Path];
    GO
    
    /*
    
    Grupo
    1 - Solicitante
    ||||||||4 - Alumnos
    ||||||||5 - Entidad
    ||||||||6 - Colaborador
    2 - Cursos
    ||||||||7 - Curso
    ||||||||8 - Edicion
    3 - Tablas Auxiliares
    ||||||||9 - Pais
    ||||||||10 - Provincia
    ||||||||11 - Población
    
    */

    La primera sentencia SELECT dentro de la CTE es el ancla y selecciona el nivel inicial (filas sin padres).  La segunda senetencia SELECT dentro de la CTE es la parte recursiva (referencia la misma CTE) y se encarga de seleccionar el proximo nivel por cada pasada hasta que no se retornen mas filas.

    En cuanto al orden de presentacion, la clave esta en formar una cadena binaria conformada por el grupo padre y nivel mas el orden que esta ocupa en el nivel indicado.

    La sentencia SELECT final hace referencia a la CTE y ordena la salida por el camino de la fila desde su grupo padre inicial.

    Puedes leer y aprender mas al respecto en los libros de Itzik Ben-Gan sobre T-SQL.

    T-SQL Fundamentals

    T-SQL Querying (Developer Reference)


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas

    • Editado HunchbackMVP viernes, 27 de julio de 2018 11:53
    • Marcado como respuesta MarcoGpex viernes, 27 de julio de 2018 12:02
    viernes, 27 de julio de 2018 11:50
  • Gracias.

    Eso es lo que pedía.

    Saludos


    Marco

    viernes, 27 de julio de 2018 12:02