2010-02-05 20 views
2

早安,如何使用PIVOT在存儲過程SQL Server 2005中加入兩種觀點

我有兩個觀點:它包含一個帳戶只能記錄與領域ACCOUNT ICCUDays和ICCUDays,ICCUEnctrSelectedRevCatsDirCost其中包含每個賬戶的多條記錄與領域ACCOUNT,UBCATEGORY和DirectCost。

我的目標:創建一個存儲過程,通過UBCATEGORY爲ICCUDays和DirectCost每個帳戶輸出一個記錄。這將是一個交叉表或關鍵點,並且必須考慮到在一個或多個直接成本類別存儲桶中可能存在空值。最後,需要將此交叉表或數據透視表發送到新表EnctrUBCatPivot。

問題:上述場景的正確PIVOT語法是什麼?鑑於我想爲無論多少UBCATEGORY條目輸入直接成本,我該如何編寫TSQL來遍歷這些條目並按帳戶和UBCATEGORY進行調整?所有這些都是在一個sproc中完成的,還是必須將它分離爲多個sprocs才能將結果寫入表中?

這裏是我到目前爲止已經編寫的代碼:

ALTER PROCEDURE [dbo].[spICCUMain] 
-- Add the parameters for the stored procedure here 

AS 
declare @columns varchar(8000) 

BEGIN 
-- SET NOCOUNT ON added to prevent extra result sets from 
-- interfering with SELECT statements. 
SET NOCOUNT ON; 

-- Insert statements for procedure here 
SELECT @columns = COALESCE(@columns + ',[' + cast(UBCATEGORYmid as varchar) + ']','[' + cast(UBCATEGORYmid as varchar)+ ']') 
FROM vwICCUEnctrSelectedRevCatsDirCost 
GROUP BY UBCATEGORYmid 


DECLARE @query VARCHAR(8000) 

SET @query = ' 
SELECT * 
FROM vwICCUEnctrSelectedRevCatsDirCost 
PIVOT 
(
MAX(DirectCost) 
FOR [UBCATEGORYmid] 
IN (' + @columns + ') 
) 
AS p' 

EXECUTE(@query) 

END 

這工作得很好,它輸出的帳號和所有各UBCATEGORY的直接成本。但是,我需要將內部連接加入到ACCOUNT上的vwICCUDAYS,以便將列添加到ICCUDays的數據透視表中。對於每個UBCATEGORYmid,最終的透視列應該是Account,ICCUDays,Direct Cost。

我不是很熟悉coalesce語法,因此無法辨別如何修改它以添加更多列,我也不確定如何/在哪裏添加內部連接語法來添加ICCUDays。

有人能指出我正確的方向嗎? 謝謝, Sid

+0

是否有任何特別的理由使用視圖作爲查詢的基礎? – 2010-02-05 19:20:23

回答

4

您需要知道PIVOT所有可能的值。因此,除非使用動態SQL,否則直接使用T-SQL很難做到這一點,而且這可以很快得到滿足。可能更好地將所有行傳回給表示層或報表編寫器,讓它橫向轉向。

這裏是一個快速的PIVOT例子,如果你事先知道所有的UBCategory值。我遺漏了ICCUDays,因爲它似乎是無關緊要的,除非在結果中有來自該視圖的列。

USE tempdb; 
GO 
SET NOCOUNT ON; 
GO 

-- who on earth is responsible for your naming scheme? 
CREATE TABLE dbo.ICCUEnctrSelectedRevCatsDirCost 
(
    Account INT, 
    UBCategory VARCHAR(10), 
    DirectCost DECIMAL(9,2) 
); 

INSERT dbo.ICCUEnctrSelectedRevCatsDirCost 
    SELECT 1, 'foo', 5.25 
    UNION SELECT 1, 'bar', 6.25 
    UNION SELECT 1, 'smudge', 8.50 
    UNION SELECT 2, 'foo', 9.25 
    UNION SELECT 2, 'brap', 2.75; 

SELECT Account,[foo],[bar],[smudge],[brap] FROM 
    dbo.ICCUEnctrSelectedRevCatsDirCost 
    -- WHERE <something>, I assume ??? 
PIVOT 
(
    MAX(DirectCost) 
    FOR UBCategory IN ([foo],[bar],[smudge],[brap]) 
) AS p; 

GO 
DROP TABLE dbo.ICCUEnctrSelectedRevCatsDirCost; 

爲了使這更有活力,你必須獲得逗號分隔DISTINCT UBCategory值列表,並構建在飛行的樞紐。因此,它可能是這樣的:

USE tempdb; 
GO 
SET NOCOUNT ON; 
GO 

-- who on earth is responsible for your naming scheme? 
CREATE TABLE dbo.ICCUEnctrSelectedRevCatsDirCost 
(
    Account INT, 
    UBCategory VARCHAR(10), 
    DirectCost DECIMAL(9,2) 
); 

INSERT dbo.ICCUEnctrSelectedRevCatsDirCost 
    SELECT 1, 'foo', 5.25 
    UNION SELECT 1, 'bar', 6.25 
    UNION SELECT 1, 'smudge', 8.50 
    UNION SELECT 2, 'foo', 9.25 
    UNION SELECT 2, 'brap', 2.75 
    UNION SELECT 3, 'bingo', 4.00; 

DECLARE @sql NVARCHAR(MAX), 
    @col NVARCHAR(MAX); 

SELECT @col = COALESCE(@col, '') + QUOTENAME(UBCategory) + ',' 
    FROM 
    (
     SELECT DISTINCT UBCategory 
     FROM dbo.ICCUEnctrSelectedRevCatsDirCost 
    ) AS x; 

SET @col = LEFT(@col, LEN(@col)-1); 

SET @sql = N'SELECT Account, $col$ FROM 
    dbo.ICCUEnctrSelectedRevCatsDirCost 
    -- WHERE <something>, I assume ??? 
PIVOT 
(
    MAX(DirectCost) 
    FOR UBCategory IN ($col$) 
) AS p;'; 

SET @sql = REPLACE(@sql, '$col$', @col); 

--EXEC sp_executeSQL @sql; 
PRINT @sql; 

GO 
DROP TABLE dbo.ICCUEnctrSelectedRevCatsDirCost; 

再到「將數據發送到一個新表」你可以使查詢的INSERT INTO ... SELECT,而不是直SELECT。當然,這看起來沒有用處,因爲爲了編寫該插入語句,您需要知道列的順序(這種方法無法保證),並且您需要爲每個潛在的UBCategory填寫列無論如何價值,所以這似乎很雞和雞蛋。

+0

那麼,你會建議讓SSRS 2005做分組,旋轉等?爲什麼建議使用動態TSQL?感謝您爲我澄清:) – SidC 2010-02-05 20:01:38

+0

嗯,我不知道如果你不知道結果集的形狀,你將如何「發送」數據到另一個表。如果您的UBCategory需要使用動態SQL進行檢索,那麼目標表如何可能已經定義了該列?前端在處理這種顯示器方面肯定更加靈活。無論如何,對於動態SQL的優點和缺點,請參閱:http://www.sommarskog.se/dynamic_sql.html – 2010-02-05 20:04:22

+0

非常感謝您的幫助! – SidC 2010-02-05 20:08:43

相關問題