2009-06-22 14 views
6

Czy jest w ogóle możliwe posiadanie funkcji wycenianej w tabeli w MSSQL, która pobiera atrybut i generuje powiązaną instrukcję SQL z funkcją Pivot?Funkcja SQL, która zwraca dane dynamicznie obracane

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

udało mi się uzyskać elastyczność Chciałem budując moje poglądy za pomocą przegubu() w przechowywanej proc, które mogą być zaplanowane do odtworzenia poglądy w razie potrzeby. Daj mi znać, jeśli ktoś chce PROC. –

Odpowiedz

6

Niestety nie, z wyjątkiem procedury przechowywanej SQL Server śledzi definicji tabeli wyjścia wszystkich widoki, funkcje itp Zatem kolumny i typy mogą nie zmieniają się dynamicznie na wejściu.

Z tego powodu nigdy nie uznałem operatora PIVOT za przydatny. Ogólnie jedynym sposobem na uzyskanie różnych danych kolumn jest traktowanie ich jako XML.

Z jakiego powodu go obracasz? Zazwyczaj jest to problem dotyczący interfejsu użytkownika, dlatego zalecam wykonanie go w interfejsie użytkownika lub w usługach SSRS itp.

+0

Problem polega na tym, że system opiera się na strukturze danych EAV, ale próbuję utworzyć dynamiczną warstwę raportowania, która nie wymaga zbyt wielu czynności konserwacyjnych. Prawdopodobnie wróci do zapisanych procesów generujących tabele statyczne na podstawie meta EAV. Dziękuję za szybką odpowiedź. –

+2

Robię podobne i używam funkcjonalności Matrix/Tablix w SSRS, aby przestawić go na render - działa bardzo zgrabnie –

+2

Muszę się nie zgadzać, że jest to problem dotyczący interfejsu użytkownika. To tak, jakby powiedzieć, że wszystkie dane stanowią problem interfejsu użytkownika. RDBS najlepiej nadaje się do krojenia i krojenia danych. W przeciwnym razie musisz przesłać więcej informacji za pośrednictwem przewodu do warstwy aplikacji, aby widget interfejsu użytkownika lub niektóre z nich mogły nim manipulować. Nie ma mowy, że chcę mieć 50000 rekordów na drucie, aby interfejs mógł wykonać widok przestawny. – Wade

1

Funkcja zwracająca tabelę musi zawsze zwracać określony schemat, więc nie jest to możliwe.

1

Oto coś, co zrobiłem, aby dostosować się do tego rodzaju funkcji (jako widok, ale funkcja byłaby zgodna z tą samą metodologią). Utknęliśmy to na końcu każdego skryptu instalacyjnego, więc po wprowadzeniu zmian do tabeli obróconej, zostaną one zebrane w ponownie wygenerowanym widoku.

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

Wykonałem następującą procedurę dynamicznego obracania wszystkich wartości w tabeli.

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 

Zastosowanie:

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 
Powiązane problemy