2010-03-31 11 views
8

J'ai une requête où je suis en train de valeurs de ligne de pivot dans les noms de colonnes et actuellement j'utilise SUM(Case...) As 'ColumnName' déclarations, comme ceci:SQL dynamique pour générer des noms de colonnes?

SELECT 
SKU1, 
SUM(Case When Sku2=157 Then Quantity Else 0 End) As '157', 
SUM(Case When Sku2=158 Then Quantity Else 0 End) As '158', 
SUM(Case When Sku2=167 Then Quantity Else 0 End) As '167' 
FROM 
OrderDetailDeliveryReview 
Group By 
OrderShipToID, 
DeliveryDate, 
SKU1 

La requête ci-dessus fonctionne très bien et me donne exactement ce que je dois. Cependant, je suis en train d'écrire les déclarations SUM(Case... à la main en fonction des résultats de la requête suivante:

Select Distinct Sku2 From OrderDetailDeliveryReview 

Est-il possible, en utilisant T-SQL dans une procédure stockée, que je peux générer dynamiquement les déclarations SUM(Case... à partir de la requête Select Distinct Sku2 From OrderDetailDeliveryReview et ensuite exécuter le code SQL résultant?

Répondre

10

Après avoir répondu à beaucoup de ces au cours des années en générant SQL pivot dynamique à partir des métadonnées, un coup d'oeil à ces exemples:

SQL Dynamic Pivot - how to order columns

SQL Server 2005 Pivot on Unknown Number of Columns

What SQL query or view will show "dynamic columns"

How do I Pivot on an XML column's attributes in T-SQL

How to apply the DRY principle to SQL Statements that Pivot Months

Dans votre cas particulier (en utilisant le pivot ANSI au lieu de la fonctionnalité de SQL Server 2005 PIVOT):

DECLARE @template AS varchar(max) 
SET @template = 'SELECT 
SKU1 
{COLUMN_LIST} 
FROM 
OrderDetailDeliveryReview 
Group By 
OrderShipToID, 
DeliveryDate, 
SKU1 
' 

DECLARE @column_list AS varchar(max) 
SELECT @column_list = COALESCE(@column_list, ',') + 'SUM(Case When Sku2=' + CONVERT(varchar, Sku2) + ' Then Quantity Else 0 End) As [' + CONVERT(varchar, Sku2) + '],' 
FROM OrderDetailDeliveryReview 
GROUP BY Sku2 
ORDER BY Sku2 

Set @column_list = Left(@column_list,Len(@column_list)-1) 

SET @template = REPLACE(@template, '{COLUMN_LIST}', @column_list) 

EXEC (@template) 
+0

Merci pour votre réponse. J'ai vu beaucoup de réponses qui utilisent 'COALESCE', mais que fait exactement cette fonction? –

+0

En outre, si j'essaie d'exécuter votre requête telle quelle, j'obtiens une erreur sur la ligne 15: "Syntaxe incorrecte près du mot clé" FROM "." Si je supprime la virgule à la fin de la ligne 14, j'obtiens alors un message d'erreur sur la ligne 3 * qui dit "Syntaxe incorrecte près de 'SUM'" Des idées sur ce qui se passe ici ou comment déboguer ça? –

+0

@Cade Roux Ok, j'ai modifié le code (mettre la virgule dans les guillemets à la fin de la ligne 14, ajouter une ligne pour couper la virgule de @column_list).Maintenant ça marche, ce qui est génial, mais je n'arrive pas à comprendre ce qui se passe entre les lignes 14 et 17. –

2

Je sais que le moteur de recherche SO n'est pas parfait, mais votre question a été répondue dans SQL Server PIVOT Column Data. Voir également Creating cross tab queries and pivot tables in SQL.

+0

@van j'ai découvert que par préfixer mes requêtes de programmation comme celui-ci, 'StackOverflow SQL Server Pivot', je reçois à Bing le site bien (bien que le moteur existant « autre » est bon: D aussi) –

+0

FYI pour ceux qui ne le savent pas: j'utilise généralement Google: "site: stackoverflow.com serveur SQL dynamique pivot cade roux" pour trouver toutes mes réponses précédentes sur ce sujet (ou sur tout). –

1

Pourquoi cela en utilisant les noms de colonnes codés en dur lorsque vous pouvez tirer tout cela dynamique de toute table? En utilisant UNPIVOT et COALESCE, je peux dynamiquement tirer une liste de colonnes de n'importe quelle table et colonnes associées pour n'importe quel enregistrement dans une liste d'enregistrements et les combiner dans une liste de noms de colonne avec des valeurs par ligne. Voici le code. Il suffit de déposer dans votre base de données et le nom de la table. La table colonne/valeur sera générée pour vous dans SQL Server. Gardez à l'esprit, pour obtenir une colonne partagée de valeurs pour les colonnes que vous souhaitez convertir en variante sql ou des chaînes de texte. Mais c'est un excellent moyen d'obtenir une liste de valeurs de colonnes avec des noms de colonnes et des types correspondants avec nos boucles while ou curseurs. Son assez rapide:

-- First get a list of all known columns in your database, dynamically... 
DECLARE @COLUMNS nvarchar(max) 
SELECT @COLUMNS = 

CASE 
WHEN A.DATA_TYPE = 'nvarchar' OR A.DATA_TYPE = 'ntext' THEN 
COALESCE(@COLUMNS + ',','') + 'CAST(CONVERT(nvarchar(4000),['+A.[name]+']) AS sql_variant) AS ['+A.[name]+']' 
WHEN A.DATA_TYPE = 'datetime' OR A.DATA_TYPE = 'smalldatetime' THEN 
COALESCE(@COLUMNS + ',','') + 'CAST(CONVERT(nvarchar,['+A.[name]+'],101) AS sql_variant) AS ['+A.[name]+']' 
ELSE 
COALESCE(@COLUMNS + ',','') + 'CAST(['+A.[name]+'] AS sql_variant) AS ['+A.[name]+']' 
END 

FROM 
(
SELECT 
A.name, 
C.DATA_TYPE 
FROM YOURDATABASENAME.dbo.syscolumns A 
INNER JOIN YOURDATABASENAME.dbo.sysobjects B ON B.id = A.id 
LEFT JOIN 
(
SELECT 
COLUMN_NAME, 
DATA_TYPE 
FROM YOURDATABASENAME.INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = 'YOURTABLENAME' 
) C ON C.COLUMN_NAME = A.name 
WHERE B.name = 'YOURTABLENAME' 
AND C.DATA_TYPE <> 'timestamp' 
) A 
-- Test that the formatted columns list is returned... 
--SELECT @COLUMNS 

-- This gets a second string list of all known columns in your database, dynamically... 
DECLARE @COLUMNS2 nvarchar(max) 
SELECT @COLUMNS2 = COALESCE(@COLUMNS2 + ',','') + '['+A.[name]+']' 
FROM 
(
SELECT 
A.name, 
C.DATA_TYPE 
FROM YOURDATABASENAME.dbo.syscolumns A 
INNER JOIN YOURDATABASENAME.dbo.sysobjects B ON B.id = A.id 
LEFT JOIN 
(
SELECT 
COLUMN_NAME, 
DATA_TYPE 
FROM YOURDATABASENAME.INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = 'YOURTABLENAME' 
) C ON C.COLUMN_NAME = A.name 
WHERE B.name = 'YOURTABLENAME' 
AND C.DATA_TYPE <> 'timestamp' 
) A 
-- Test that the formatted columns list is returned... 
--SELECT @COLUMNS2 


-- Now plug in the list of the dynamic columns list into an UNPIVOT to get a Column Name/Column Value list table... 
DECLARE @sql nvarchar(max) 
SET @sql = 
' 
SELECT 
ColumnName,ColumnValue 
FROM 
(
SELECT 
'[email protected]+' 
FROM YOURDATABASENAME.dbo.YOURTABLENAME 
WHERE CHANGE_ID IN (SELECT ChangeId FROM YOURDATABASENAME.dbo.OperatorProcess WHERE OperatorProcessID = 3) 
) AS SourceTable 
UNPIVOT 
(
ColumnValue FOR ColumnName IN ('[email protected]+') 
) AS PivotTable 
' 

EXEC (@sql) 
+0

ligne 9 résultats en erreur: "Nom de colonne non valide" CHANGE_ID "." – JESii

0
-- Darshankar Madhusudan i can do dynamic columnheading table easly... 
--thanks 
declare @incr int = 1, 
     @col int, 
     @str varchar(max), 
     @tblcrt varchar(max), 
     @insrt varchar(max), 
     set @tblcrt = 'DECLARE @Results table ('   
     set @str = ''  
     set @insrt = '' 
    select @col = max(column_id) From tempdb.sys.all_columns where object_id = object_id('tempdb.dbo.#aaa') 
    while @incr <= @col 
     BEGIN 
      SELECT @STR = @STR +case when @incr = 1 then '''' else ',''' end +rtrim(ltrim(NAME))+'''' FROM TEMPDB.SYS.ALL_COLUMNS WHERE OBJECT_ID = OBJECT_ID('TEMPDB.DBO.#AAA') and column_id = @incr 
      set @tblcrt = @tblcrt + case when @incr = 1 then '' else ',' end + 'Fld'+CAST(@incr as varchar(3)) +' varchar(50)' 
      set @insrt = @insrt + case when @incr = 1 then '' else ',' end + 'Fld'+CAST(@incr as varchar(3)) 
      SET @INCR = @INCR + 1 
     END 
     set @tblcrt = @tblcrt + ')' 
     set @insrt = 'insert into @Results('[email protected]+') values (' + @STR +')' 
     set @tblcrt = @tblcrt+ ';' + @insrt + 'select * from @Results ' 
exec(@tblcrt)