2009-06-22 6 views
6

Est-il tout à fait possible d'avoir une fonction table évaluée dans MSSQL qui prend un attribut et génère une instruction SQL associée avec la fonction Pivot?SQL Fonction qui renvoie dynamiquement des données pivotées

CREATE FUNCTION dbo.fnPivot (@EntityTypeID int) 
RETURNS TABLE 
AS 
BEGIN 
    DECLARE @SQL varchar(MAX); 
    DECLARE @COLS varchar(MAX); 

    select @COLS=coalesce(@COLS+',','')+'['+Name+']'from c_EntityAttribute WHERE EntityTypeID = @EntityTypeID; 

    SET @SQL = 'SELECT * FROM (SELECT EntityInstanceID, AttributeName, Value FROM v_EntityElementData WHERE EntityTypeID = 1) as s'; 
    SET @SQL = @SQL + 'PIVOT (MIN(Value) FOR AttributeName IN (' + @COLS + ')) AS p'; 

    RETURN EXEC sp_ExecuteSQL @SQL ; 
END 
+0

J'ai réussi à obtenir la flexibilité que je voulais en construisant mon point de vue (en utilisant PIVOT) dans un proc stocké qui peut être programmé pour reproduire les vues en cas de besoin. Faites-moi savoir si quelqu'un veut le PROC. –

Répondre

6

Malheureusement non, à l'exception des procédures stockées SQL Server assure le suivi de la définition de la table de la sortie de toutes les vues, fonctions, etc. Ainsi, les colonnes et les types ne peuvent pas changer de manière dynamique sur l'entrée.

Pour cette raison, je n'ai jamais trouvé l'opérateur PIVOT utile. Généralement, la seule façon d'extraire les données de colonne est de les traiter en XML.

Pour quelle raison le faites-vous pivoter? Ceci est généralement une question d'interface utilisateur, et donc je recommande de le faire à l'interface utilisateur, ou SSRS etc.

+0

Le problème est que le système repose sur une structure de données EAV, mais j'essaie de construire une couche de reporting dynamique qui ne nécessite pas trop de maintenance. Va probablement retourner aux procs stockés qui génèrent les tables statiques basées sur la méta EAV. Merci pour la réponse rapide. –

+2

Je fais similaire et utilise la fonctionnalité Matrix/Tablix dans SSRS pour le faire pivoter sur rendu - fonctionne très bien –

+2

Je ne suis pas d'accord que c'est une question d'interface utilisateur. C'est comme dire que toutes les données sont une préoccupation de l'assurance-chômage. Le RDBS est le mieux adapté pour découper et découper des données. Sinon, vous devez envoyer beaucoup plus sur le fil de la couche de l'application juste pour que le widget UI ou un tel peut le manipuler. Non, je veux 50000 enregistrements sur le fil de sorte que l'interface utilisateur peut faire une vue de pivot. – Wade

1

Une fonction de valeur table doit toujours renvoyer un schéma spécifié, ce qui n'est pas possible.

1

Voici quelque chose que j'ai fait pour accommoder ce type de fonctionnalité (en tant que vue, mais une fonction suivrait la même méthodologie). Nous l'avons placé à la fin de chaque script d'installation. Ainsi, lorsque des modifications sont apportées à la table en cours de pivotement, elles sont récupérées dans la vue générée à nouveau.

IF EXISTS (SELECT * 
     FROM sys.objects 
     WHERE object_id = Object_id(N'[dbo].[vwYourView]') 
       AND type IN (N'V')) 
BEGIN 
    DROP VIEW [dbo].[vwYourView] 
END 
GO        

Declare @cols VARCHAR(MAX) 

Select @cols = COALESCE(@cols + ',[' + YourColumn+ ']', 
           '[' + YourColumn+ ']') 
           FROM YourTable 
           Order By YourColumn 

DECLARE @query VARCHAR(MAX) 
Set @query = 
N' 
Create View vwYourView 
AS 
Select * FROM YourTable 
Pivot (
    MAX(YourVal) 
    FOR YourColumn IN('+ 
     @cols 
    +') 
) AS pvt 
' 

Execute(@query) 

Select * FROM [vwYourView] 
1

J'ai effectué la procédure suivante pour faire pivoter dynamiquement toutes les valeurs d'une table.

CREATE OR ALTER PROC dbo.spDynamicPivot (
    @Query NVARCHAR(MAX)    --The query to pivot 
, @AggregateFunction NVARCHAR(MAX) --The aggregation function surrounding the column name to be pivoted 
, @ValueColumn NVARCHAR(MAX)  --The value column from which to create columns 
, @ResultTable NVARCHAR(MAX) = NULL --An optional table name into which the results will be stored. Note, this unfortunately will not work with #temp tables. 
) AS BEGIN 

    SET XACT_ABORT ON; 
    SET NOCOUNT ON; 

    DECLARE @cols NVARCHAR(MAX); 

    DECLARE @sql NVARCHAR(MAX) = 'SELECT @cols = ISNULL(@cols + '','', '''') + ''['' + Val + '']'' FROM (SELECT DISTINCT Val = ' + @ValueColumn + ' FROM (' + @Query + ') a) b;'; 
    DECLARE @paramDef NVARCHAR(MAX) = '@cols NVARCHAR(MAX) OUTPUT'; 

    EXEC sp_executesql @sql, @paramDef, @cols = @cols OUTPUT; 

    DECLARE @resultSetSql NVARCHAR(MAX) = IIF(ISNULL(@ResultTable, '') <> '', 'INTO ' + @ResultTable + ' ', ''); 
    SET @sql = 'SELECT * ' + @resultSetSql + 'FROM (' + @Query + ') q PIVOT(' + @AggregateFunction + ' FOR ' + @ValueColumn + ' IN (' + @cols + ')) p'; 

    EXEC sp_executesql @sql; 

END 

Utilisation:

DROP TABLE IF EXISTS #t; 
CREATE TABLE #t (Name VARCHAR(50), Age INT, NetWorth FLOAT); 
INSERT INTO #t VALUES 
('Bill', 50, 250), 
('Barb', 17, 15), 
('Fred', 25, 30), 
('Bill', 25, 100), 
('Kahless', 90000, 4E10) 

--Displaying results directly 
EXEC dbo.spDynamicPivot @Query = 'SELECT * FROM #t', @AggregateFunction = 'AVG(NetWorth)', @ValueColumn = 'Name' 

--Or writing them into a table for additional use 
DROP TABLE IF EXISTS tempdb.dbo.MyTable; 
EXEC dbo.spDynamicPivot @Query = 'SELECT * FROM #t', @AggregateFunction = 'AVG(NetWorth)', @ValueColumn = 'Name', @ResultTable = 'tempdb.dbo.MyTable' 

SELECT * FROM tempdb.dbo.MyTable 
Questions connexes