none
¿Cómo Implementar consulta en SqlServer para que el resultado devuelva columnas en vez de filas ? RRS feed

  • Pregunta

  • Hola ...

    Cuando ejecuto la siguiente consulta:

    SELECT NombreFamilia FROM CRMv2_000784..A_ArticuloFamilia  GROUP BY NombreFamilia

    me devuelve :

    NombreIdFamilia
    Camisas
    Zapatos
    Pantalones

    Como puedo hacer ('usando un cursor') para que me devuelva como columnas de una tabla

    Camisas   Zapatos  Pantalones


    EFRAIN MEJIAS C VALENCIA - VENEZUELA

    viernes, 12 de febrero de 2021 14:32

Respuestas

  • OK, te pongo un ejemplo con un cursor, aunque insisto en que esta NO es la forma recomendada de hacerlo.

    Para empezar, construyamos una tabla con datos de prueba para usarla como ejemplo.

    create table prueba (
        NombreFamilia varchar(50),
    	OtraCosa int
    )
    go
    insert prueba values('Camisas',1), ('Zapatos',2), ('Camisas',3), ('Pantalones',4), ('Zapatos',5)
    go

    Sobre esta tabla supongamos que queremos construir una sentencia PIVOT similar a la que ongo a continuación. Este ejemplo tiene los valores de las columnas escritos de manera "fija", pero es conveniente hacer una prueba como esta para cerciorarse de que la sentencia funciona correctamente. Después de probarla, construiremos el código para generarla dinámicamente con un cursor.

    SELECT 'Suma' AS Titulo,   
    [Camisas], [Zapatos], [Pantalones]  
    FROM  prueba
    PIVOT  
    (  
    Sum(OtraCosa)  
    FOR NombreFamilia IN ([Camisas], [Zapatos], [Pantalones])  
    ) AS PivotTable; 

    Una vez que la hayamos probado y sepamos que hace lo que queremos, nos fijamos en que tiene en dos sitios la lista de columnas. Entonces escribimos un bucle con un cursor que genere esa lista. Después lo concatenamos con el resto de la sentencia, y lo mandamos ejecutar:

    DECLARE @sql NVARCHAR(4000) = ''
    DECLARE c CURSOR LOCAL FAST_FORWARD
    FOR
      SELECT DISTINCT NombreFamilia FROM prueba ORDER BY NombreFamilia
     
    OPEN c;
    DECLARE @n varchar(50)
    FETCH c INTO @n;
     
    WHILE (@@FETCH_STATUS = 0)
    BEGIN
      IF @sql<>'' SET @sql+=','
      SET @sql += '['+@n+']'
      FETCH c INTO @n;
    END
     
    CLOSE c;
    DEALLOCATE c;
    
    set @sql ='SELECT ''Suma'' AS Titulo, '   
    +@sql+  
    ' FROM  prueba
    PIVOT  
    (  
    Sum(OtraCosa)  
    FOR NombreFamilia IN ('+@sql+')  
    ) AS PivotTable;'
    
    EXEC sp_executesql @sql
    go
    

    Este es el resultado:

    Captura de pantalla

    viernes, 12 de febrero de 2021 18:03

Todas las respuestas

  • Bien, lo normal cuando quieres sacar las filas como columnas es usar la cláusula PIVOT. El problema es que la PIVOT requiere poner "fijos" los nombres de las columnas, cosa que en tu caso no te es útil porque precisamente esos nombres son tus variables. Cuando esto se necesita, hay que hacer lo que se llama un "pivot con sql dinámico". Básicamente consiste en que primero se consultan las filas, entonces el resultado se concatena en un string, luego el string se concatena a una pivot, y finalmente el resultado se ejecuta como sql dinámico.

    Tradicionalmente esta concatenación de datos se ha venido haciendo con un cursor, pero como la tendencia moderna es la de "cursor=caca", se pueden usar otras técnicas. Por ejemplo, está el truco de usar un "select...for xml" en la sentencia que devuelve las filas, después hacer reemplazos en el xml en forma de string, y eso ya te da la cadena que hay que concatenar en el PIVOT.

    Tienes un ejemplo con explicaciones paso a paso aquí:

    https://www.codingvila.com/2021/01/dynamic-pivot-query-sql.html

    viernes, 12 de febrero de 2021 16:23
  • Hola ::

    Alberto Poblacion  

    Si pudieras mostrarme como se hace con un cursor seria genial



    EFRAIN MEJIAS C VALENCIA - VENEZUELA

    viernes, 12 de febrero de 2021 16:49
  • OK, te pongo un ejemplo con un cursor, aunque insisto en que esta NO es la forma recomendada de hacerlo.

    Para empezar, construyamos una tabla con datos de prueba para usarla como ejemplo.

    create table prueba (
        NombreFamilia varchar(50),
    	OtraCosa int
    )
    go
    insert prueba values('Camisas',1), ('Zapatos',2), ('Camisas',3), ('Pantalones',4), ('Zapatos',5)
    go

    Sobre esta tabla supongamos que queremos construir una sentencia PIVOT similar a la que ongo a continuación. Este ejemplo tiene los valores de las columnas escritos de manera "fija", pero es conveniente hacer una prueba como esta para cerciorarse de que la sentencia funciona correctamente. Después de probarla, construiremos el código para generarla dinámicamente con un cursor.

    SELECT 'Suma' AS Titulo,   
    [Camisas], [Zapatos], [Pantalones]  
    FROM  prueba
    PIVOT  
    (  
    Sum(OtraCosa)  
    FOR NombreFamilia IN ([Camisas], [Zapatos], [Pantalones])  
    ) AS PivotTable; 

    Una vez que la hayamos probado y sepamos que hace lo que queremos, nos fijamos en que tiene en dos sitios la lista de columnas. Entonces escribimos un bucle con un cursor que genere esa lista. Después lo concatenamos con el resto de la sentencia, y lo mandamos ejecutar:

    DECLARE @sql NVARCHAR(4000) = ''
    DECLARE c CURSOR LOCAL FAST_FORWARD
    FOR
      SELECT DISTINCT NombreFamilia FROM prueba ORDER BY NombreFamilia
     
    OPEN c;
    DECLARE @n varchar(50)
    FETCH c INTO @n;
     
    WHILE (@@FETCH_STATUS = 0)
    BEGIN
      IF @sql<>'' SET @sql+=','
      SET @sql += '['+@n+']'
      FETCH c INTO @n;
    END
     
    CLOSE c;
    DEALLOCATE c;
    
    set @sql ='SELECT ''Suma'' AS Titulo, '   
    +@sql+  
    ' FROM  prueba
    PIVOT  
    (  
    Sum(OtraCosa)  
    FOR NombreFamilia IN ('+@sql+')  
    ) AS PivotTable;'
    
    EXEC sp_executesql @sql
    go
    

    Este es el resultado:

    Captura de pantalla

    viernes, 12 de febrero de 2021 18:03