2010-03-05 11 views
0

J'ai une table comme ci-dessousAide Pivot/Unpivot

Name Priority Date  
------------------------- 
A   2   d1 
B   3   d2 

Comment écrire une requête pour obtenir le résultat ci-dessous

ColumnNames d1  d2 
-------------------------- 
Name   A  B 
Priority  2  3 

Merci

+0

Cela semble familier ... est thi s des mêmes exigences que la question que vous avez posée l'autre jour? – Aaronaught

Répondre

3

Voici la solution que je promis:

EDIT: J'ai modifié ma réponse pour répondre addit questions ionales par le PO.

Quelques choses à noter:

  • La fonction STUFF: Ceci est utilisé pour convertir la chaîne XML en une chaîne régulière (et pour enlever la première virgule)
  • Group By (I a volé ce billet depuis OMG Ponies): Vous devez faire ceci pour vous assurer que vous n'avez pas de dates en double
  • Assurez-vous qu'il n'y a pas trop de dates dans la table avant d'exécuter ceci. Trop de colonnes peuvent être un problème
  • NVARCHAR: J'ai utilisé ceci à la place de VARCHAR pour la variable @sql car sp_ExecuteSQL l'exige.
  • CONVERT (VARCHAR, DateColumn, 101): Je l'ai fait parce que si vous ne convertissez pas la date en chaîne, cela ne marchera pas. 101 résultats dans ce: mm/jj/aaaa mais vous pouvez utiliser tout ce dont vous avez besoin (assurez-vous que le 2 fois il est utilisé dans ce script correspond)
  • Pour que cela fonctionne pour plusieurs colonnes, vous devez d'abord utiliser UNPIVOT et convertir toutes les colonnes au même type de données (plus d'informations sous le code)
  • Il est important de noter que pour concaténer des chaînes, elles doivent être du même type de données, avec la même taille (dans mon cas, elles sont toutes les deux NVARCHAR (MAX))

Lire this page pour plus d'informations sur la conversion de dates en chaînes.

Cela dit, voici le code:

-- table with multiple columns 
CREATE TABLE #TBL ( 
    NameColumn VARCHAR(10), 
    PriorityColumn INT, 
    AnotherColumn FLOAT, 
    DateColumn DATETIME 
) 


-- Insert the test data 
INSERT INTO #TBL VALUES ('a', 1, 7.2, '1/1/2000') 
INSERT INTO #TBL VALUES ('a', 2, 8.9, '1/2/2000') 
INSERT INTO #TBL VALUES ('a', 2, 53.2, '1/3/2000') 
INSERT INTO #TBL VALUES ('a', 3, 9.12, '1/4/2000') 
INSERT INTO #TBL VALUES ('b', 2, 1.26, '1/1/2001') 


DECLARE 
    @sql NVARCHAR(max), 
    @dates NVARCHAR(max) 


-- I separated this to make the code easier to read 
SET @dates = STUFF(
    (
     SELECT N',[' + CONVERT(VARCHAR, DateColumn, 101) + ']' AS [text()] 
     FROM #TBL 
     GROUP BY DateColumn 
     ORDER BY DateColumn 
     FOR XML PATH('') 
    ), 1, 1, N'' 
) 


-- I will break this part of the code up below 
SET @sql = N'SELECT 
    * 
FROM (
    SELECT 
     ColumnName, 
     ColumnValue, 
     CONVERT(VARCHAR, DateColumn, 101) AS DateString 
    FROM (
     SELECT 
      CAST(NameColumn AS VARCHAR(100)) AS NameColumn, 
      CAST(PriorityColumn AS VARCHAR(100)) AS PriorityColumn, 
      CAST(AnotherColumn AS VARCHAR(100)) AS AnotherColumn, 
      DateColumn 
     FROM #TBL 
    ) P 
    UNPIVOT (
     ColumnValue 
     FOR ColumnName IN (NameColumn, PriorityColumn, AnotherColumn) 
    ) UNPIV 
) P2 
PIVOT (
    MAX(ColumnValue) 
    FOR DateString IN (' + @dates + N') 
) PIV' 

EXECUTE dbo.sp_ExecuteSQL @sql 


DROP TABLE #TBL 

permet d'exécuter à travers ce un peu

-- I first do an UNPIVOT on all of the columns I want to pivot on, at the same time, converting them to the same datatype 
SELECT 
    ColumnName, 
    ColumnValue, 
    CONVERT(VARCHAR, DateColumn, 101) AS DateString 
FROM (
    SELECT 
     CAST(NameColumn AS VARCHAR(100)) AS NameColumn, 
     CAST(PriorityColumn AS VARCHAR(100)) AS PriorityColumn, 
     CAST(AnotherColumn AS VARCHAR(100)) AS AnotherColumn, 
     DateColumn 
    FROM #TBL 
) P 
UNPIVOT (
    ColumnValue 
    FOR ColumnName IN (NameColumn, PriorityColumn, AnotherColumn) 
) UNPIV 

Une fois que je fais cela, les données ressemblera à quelque chose comme ceci:

ColumnName ColumnValue DateString 
---------------------------------- 
NameColumn  a  01/01/2000 
PriorityColumn 1  01/01/2000 
AnotherColumn 7.2  01/01/2000 
NameColumn  a  01/02/2000 
PriorityColumn 2  01/02/2000 
AnotherColumn 8.9  01/02/2000 
NameColumn  a  01/03/2000 
PriorityColumn 2  01/03/2000 
AnotherColumn 53.2  01/03/2000 
NameColumn  a  01/04/2000 
PriorityColumn 3  01/04/2000 
AnotherColumn 9.12  01/04/2000 
NameColumn  b  01/01/2001 
PriorityColumn 2  01/01/2001 
AnotherColumn 1.26  01/01/2001 

Ensuite, nous pouvons utiliser PIVOT comme ceci pour obtenir toutes les colonnes dont nous avons besoin:

PIVOT (
    MAX(ColumnValue) 
    FOR DateString IN (' + @dates + N') 
) PIV 
+0

Confus. J'obtiens le concept mais incapable de m'appliquer à mon problème pour la sortie désirée. – stackoverflowuser

+0

est le type de données de la colonne de dates DATETIME? Si c'est le cas, vous devrez écrire du code SQL dynamique. Je peux vous donner plus de détails quand je rentre à la maison. En ce moment, je n'ai pas accès à mon code. –

+0

oui le type de données est DateTime – stackoverflowuser

2

Est-ce que vous cherchez:

create table NameAndDate (NameCol varchar(200), DateCol datetime); 

insert into NameAndDate (NameCol, DateCol) values ('A', '2010-03-04'); 
insert into NameAndDate (NameCol, DateCol) values ('B', '2010-03-05'); 

select * from NameAndDate; 

select * from NameAndDate 
pivot (
max(NameCol) 
for DateCol 
in ([2010-03-04], [2010-03-05])) 
as PivotResults; 

Cela me donne les résultats suivants:

NameCol  DateCol 
--------------------------------------- 
1 A   2010-03-04 00:00:00.0000 
2 B   2010-03-05 00:00:00.0000 


    2010-03-04 2010-03-05 
------------------------- 
1 A   B 

Notez que cela nécessite de connaître les dates à l'avance, lorsque vous écrire la requête (sauf si vous utilisez le SQL dynamique comme mentionné par Gabriel).

Edit:

J'essayé d'utiliser l'approche de Poneys OMG, mais a dû le modifier comme ceci:

declare @Dates nvarchar(max) 
set @Dates = 
    (select '['+ convert(varchar, NameAndDate.DateCol) + '],' 
    from NameAndDate 
    group by NameAndDate.DateCol 
    order by NameAndDate.DateCol 
    for xml path('')) 
set @Dates = left(@Dates, len(@Dates) - 1) 

declare @SQL nvarchar(4000) 
set @SQL = 
    'select * 
    from NameAndDate 
    pivot (
    max(NameCol) 
    for DateCol in (' + @Dates + ')) 
    as PivotResults' 

exec sp_executesql @SQL 

Cela me donne ces résultats:

Mar 4 2010 12:00AM Mar 5 2010 12:00AM 
------------------------------------------ 
1 A     B 
+0

merci saxon !! – stackoverflowuser

2

Utilisation:

DECLARE @SQL NVARCHAR(4000) 
DECLARE @dates NVARCHAR(max) 

SET @dates = SELECT '['+ t.date +"]," 
       FROM TABLE t 
      GROUP BY t.date 
      ORDER BY t.date 
      FOR XML PATH('') 

@SQL = 'SELECT * 
      FROM TABLE 
     PIVOT(MAX(name) FOR date IN (@dates)) AS pvt' 

BEGIN 

    EXEC sp_executesql @SQL, N'@dates NVARCHAR(max)', @dates 

END 
+0

merci omg poneys. – stackoverflowuser