2010-08-27 3 views
1

J'ai la disposition de tableau suivante. Chaque valeur de ligne sera toujours unique. Il n'y aura jamais plus d'une instance du même ID, nom et ligne. Je souhaite interroger les données afin que le champ Ligne devienne une colonne. Si la valeur existe, un 1 est appliqué dans les données de champ, sinon un 0. Par ex.Champs de transformation de table TSQL => Colonnes

Id Name Z Y X W 
1 A 1 0 0 0 
2 B 0 1 0 0 
3 C 0 0 1 1 
4 D 0 0 0 1 

Les noms de champs W, X, Y, Z ne sont que des exemples de valeurs de champ, donc je ne peux pas demander à un opérateur de vérifier explicitement, par exemple, « X », « Y » ou « Z '. Ceux-ci peuvent changer à tout moment et ne sont pas limités à un ensemble de valeurs finies. Les noms de colonne dans le jeu de résultats doivent refléter les valeurs de champ uniques en tant que colonnes.

Une idée de comment je peux accomplir cela?

+0

Est-ce que 'Z Y X W' est fixé? –

+0

Oui, dans le résultat ils seraient les noms des colonnes - ils pourraient s'appeler n'importe quoi. –

+0

"Si la valeur existe, un 1 est appliqué dans les données de champ" - cela signifie-t-il que 1 indique au moins une instance de la valeur, ou ce nombre doit-il refléter le nombre de cette valeur associée au groupe? –

Répondre

6

C'est une requête pivot standard.

Si 1 représente un indicateur booléen - Utilisation:

SELECT t.id, 
     t.name, 
     MAX(CASE WHEN t.line = 'Z' THEN 1 ELSE 0 END) AS Z, 
     MAX(CASE WHEN t.line = 'Y' THEN 1 ELSE 0 END) AS Y, 
     MAX(CASE WHEN t.line = 'X' THEN 1 ELSE 0 END) AS X, 
     MAX(CASE WHEN t.line = 'W' THEN 1 ELSE 0 END) AS W 
    FROM TABLE t 
GROUP BY t.id, t.name 

Si 1 représente le nombre d'enregistrements avec cette valeur pour le groupe, utilisez:

SELECT t.id, 
     t.name, 
     SUM(CASE WHEN t.line = 'Z' THEN 1 ELSE 0 END) AS Z, 
     SUM(CASE WHEN t.line = 'Y' THEN 1 ELSE 0 END) AS Y, 
     SUM(CASE WHEN t.line = 'X' THEN 1 ELSE 0 END) AS X, 
     SUM(CASE WHEN t.line = 'W' THEN 1 ELSE 0 END) AS W 
    FROM TABLE t 
GROUP BY t.id, t.name 
+0

Pourquoi MAX est-il nécessaire? – flayto

+1

@flato: Pour obtenir la valeur la plus élevée pour cette colonne dans le groupe - c'est le MAX qui permet au jeu de résultats de "s'aplatir" comme vous le voyez dans la sortie attendue. Parce que sinon, vous verriez une comparaison de lignes par colonnes pour chaque paire 'id' et' name'. –

+0

+1 Approche légèrement différente de la mienne qui m'a troublé momentanément d'où un commentaire éphémère que vous avez peut-être vu! –

2

Edité mise à jour suivante en question

SQL Server ne prend pas en charge le pivotement dynamique. Pour ce faire, vous pouvez utiliser SQL dynamique pour générer une requête le long des lignes suivantes.

SELECT 
     Id ,Name, 
     ISNULL(MAX(CASE WHEN Line='Z' THEN 1 END),0) AS Z, 
     ISNULL(MAX(CASE WHEN Line='Y' THEN 1 END),0) AS Y, 
     ISNULL(MAX(CASE WHEN Line='X' THEN 1 END),0) AS X, 
     ISNULL(MAX(CASE WHEN Line='W' THEN 1 END),0) AS W 
FROM T 
GROUP BY Id ,Name 

Ou une alternative que j'ai lu mais pas réellement essayé est de tirer parti de la fonction Accès Transform en mettant en place une base de données d'accès à une table liée pointant à la table SQL Server puis interroger la base de données Access de SQL Server !

1

En supposant que vous avez un nombre fini de valeurs pour la ligne que vous pouvez énumérer:

declare @MyTable table (
    Id int, 
    Name char(1), 
    Line char(1) 
) 

insert into @MyTable 
    (Id, Name, Line) 
    select 1,'A','Z' 
    union all 
    select 2,'B','Y' 
    union all 
    select 3,'C','X' 
    union all 
    select 3,'C','W' 
    union all 
    select 4,'D','W' 

SELECT Id, Name, Z, Y, X, W 
    FROM (SELECT Id, Name, Line 
      FROM @MyTable) up 
    PIVOT (count(Line) FOR Line IN (Z, Y, X, W)) AS pvt 
    ORDER BY Id 
0

Comme vous utilisez SQL Server, vous pouvez éventuellement utiliser l'opérateur PIVOT prévu à cet effet.

+1

Oui. [SQLMenace] (http://stackoverflow.com/questions/3586909/tsql-table-transformation-fields-columns/3587015#3587015) et [I] (http://stackoverflow.com/questions/3586909/tsql-table -transformation-fields-columns/3586982 # 3586982) ont tous deux fourni des réponses en utilisant PIVOT. –

+0

SQL Server * 2005 + * prend en charge PIVOT; Oracle 11gR2 est le seul autre DB que je connaisse qui supporte 'PIVOT' –

2

Voici la version dynamique

table de test

create table #test(id int,name char(1),line char(1)) 

insert #test values(1 , 'A','Z') 
insert #test values(2 , 'B','Y') 
insert #test values(3 , 'C','X') 
insert #test values(4 , 'C','W') 
insert #test values(5 , 'D','W') 
insert #test values(5 , 'D','W') 
insert #test values(5 , 'D','P') 

Lancez maintenant ce

declare @names nvarchar(4000) 

SELECT @names ='' 
    SELECT @names = @names + line +', ' 
    FROM (SELECT distinct line from #test) x 

SELECT @names = LEFT(@names,(LEN(@names) -1)) 

exec(' 
SELECT * 
FROM(
SELECT DISTINCT Id, Name,Line 
FROM #test 
    ) AS pivTemp 
PIVOT 
( COUNT(Line) 
    FOR Line IN (' + @names +') 
) AS pivTable ') 

Maintenant, ajoutez une ligne à la table et exécuter la requête ci-dessus à nouveau et vous verrez la B

insert #test values(5 , 'D','B') 

Attention: Bien sûr tous les problèmes avec SQL dynamiques appliquent, si vous pouvez utiliser sp_executesql mais étant donné que les paramètres ne sont pas utiliser comme dans la requête il n'y a vraiment pas de point

0

Si vous faites cela pour un SQL Server Reporting Reporting (SSRS), ou pourrait éventuellement passer à l'utilisation d'un, puis arrêtez maintenant et allez jeter un contrôle Matrix sur votre rapport. Poof! Vous avez terminé! Heureux comme une palourde avec vos données pivotées.

0

Voici une approche plutôt exotique (en utilisant des exemples de données de l'ancienne base de données Northwind). Il est adapté de la version here, qui ne fonctionnait plus en raison de la dépréciation de DBCC RENAMECOLUMN et de l'ajout de PIVOT en tant que mot-clé.

set nocount on 
create table Sales ( 
    AccountCode char(5), 
    Category varchar(10), 
    Amount decimal(8,2) 
) 
--Populate table with sample data 
insert into Sales 
select customerID, 'Emp'+CAST(EmployeeID as char), sum(Freight) 
from Northwind.dbo.orders 
group by customerID, EmployeeID 
create unique clustered index Sales_AC_C 
on Sales(AccountCode,Category) 
--Create table to hold data column names and positions 
select A.Category, 
     count(distinct B.Category) AS Position 
into #columns 
from Sales A join Sales B 
on A.Category >= B.Category 
group by A.Category 
create unique clustered index #columns_P on #columns(Position) 
create unique index #columns_C on #columns(Category) 
--Generate first column of Pivot table 
select distinct AccountCode into Pivoted from Sales 
--Find number of data columns to be added to Pivoted table 
declare @datacols int 
select @datacols = max(Position) from #columns 
--Add data columns one by one in the correct order 
declare @i int 
set @i = 0 
while @i < @datacols begin 
    set @i = @i + 1 
--Add next data column to Pivoted table 
    select P.*, isnull(( 
    select Amount 
    from Sales S join #columns C 
    on C.Position = @i 
    and C.Category = S.Category 
    where P.AccountCode = S.AccountCode),0) AS X 
    into PivotedAugmented 
    from Pivoted P 
--Name new data column correctly 
    declare @c sysname 
    select @c = Category 
    from #columns 
    where Position = @i 
    exec sp_rename '[dbo].[PivotedAugmented].[X]', @c, 'COLUMN' 
--Replace Pivoted table with new table 
    drop table Pivoted 
    select * into Pivoted from PivotedAugmented 
    drop table PivotedAugmented 
end 
select * from Pivoted 
go 
drop table Pivoted 
drop table #columns 
drop table Sales 
Questions connexes