¿Cómo pasar datos de filas a columnas – SQL Server?

publicado por: Anonymous

Buenas estoy mostrando un listado de personas con varios nombres de artefactos que compraron, al momento de mostrar el listado me salen nombres de personas repetidas pero con diferentes nombres de artefactos, lo que yo quisiera es hacer que ya no se muestren el listado de personas repetidas con artefactos diferentes, si no mostrar un listado de personas que tengan columnas con artefactos diferentes. He intentado hacer pero no me sale, aquí mi avance:

Código:

SELECT*
FROM
(
SELECT DISTINCT TOP 100 
    p.IdPersona, 
    p.ApellidoPaterno, 
    p.ApellidoMaterno, 
    p.Nombre, 
    p.DNI,
    p.FechaNacimiento,
    d.Descripcion as DNombreArtefacto
FROM Personas p
JOIN DArtefactos d ON p.IdDArtefactos = d.IdDArtefactos
)
AS SourceTable PIVOT
(
count(DNombreArtefacto) for DNombreArtefacto in ([DNombreArtefacto1],[DNombreArtefacto2])
) AS PivoteTable;

Con ese código solo me cargan ceros en las columnas de los nombres de artefactos pero no sus nombres.

solución

Aquí hay un ejemplo de como convertir los valores de filas en columnas. Existe una forma de hacerlo de forma dinámica, pero es importante que se entienda primero como hacerlo de forma estática para prevenir errores.

WITH ctePersonasArtefactos AS(
    SELECT 
        p.IdPersona      , 
        p.ApellidoPaterno, 
        p.ApellidoMaterno, 
        p.Nombre         , 
        p.DNI            ,
        p.FechaNacimiento,
        d.Descripcion    AS DNombreArtefacto,
        ROW_NUMBER() OVER( PARTITION BY p.IdPersona ORDER BY d.Descripcion) AS NumArtefacto
    FROM Personas p
    JOIN DArtefactos d ON p.IdDArtefactos = d.IdDArtefactos
)
SELECT IdPersona      , 
       ApellidoPaterno, 
       ApellidoMaterno, 
       Nombre         , 
       DNI            ,
       FechaNacimiento,
       MAX( CASE WHEN NumArtefacto = 1 THEN DNombreArtefacto END) AS DNombreArtefacto1,
       MAX( CASE WHEN NumArtefacto = 2 THEN DNombreArtefacto END) AS DNombreArtefacto2,
       MAX( CASE WHEN NumArtefacto = 3 THEN DNombreArtefacto END) AS DNombreArtefacto3,
       MAX( CASE WHEN NumArtefacto = 4 THEN DNombreArtefacto END) AS DNombreArtefacto4,
       MAX( CASE WHEN NumArtefacto = 5 THEN DNombreArtefacto END) AS DNombreArtefacto5,
       MAX( CASE WHEN NumArtefacto = 6 THEN DNombreArtefacto END) AS DNombreArtefacto6
FROM ctePersonasArtefactos
GROUP BY IdPersona    , 
       ApellidoPaterno, 
       ApellidoMaterno, 
       Nombre         , 
       DNI            ,
       FechaNacimiento;

Existen varios puntosen esta consulta:

  • Primero agregué la función ROW_NUMBER() para poder controlar que todos los artefactos puedan ser identificados de una forma más controlable (siempre iniciando en 1 y sin saltos).
  • Como ese valor no lo puedo referenciar en el resto de la consulta, lo incluyo en una CTE (common table expression), la cual es como una subconsulta o “tabla derivada” que, en otras situaciones, puede tener más facultades.
  • Al final, sólo utilicé una técnica disponible desde antes de que existiera la instrucción PIVOT para convertir filas en columnas. Esta técnica es la que prefiero porque es más versatil y llega a ser más eficiente. Esto lo aprendí de este artículo en inglés.
Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *