2

おはよう、

2つのビューがあります。ACCOUNTフィールドとICCUDaysフィールドを持つアカウントごとに1つのレコードを含むICCUDays、ACCOUNT、UBCATEGORY、およびDirectCostフィールドを持つアカウントごとに複数のレコードを含むICCUEnctrSelectedRevCatsDirCostです。

私の目標:IBCATEGORYによるICCUDaysとDirectCostを使用して、ACCOUNTごとに1つのレコードを出力するストアドプロシージャを作成すること。これはクロス集計またはピボットになり、1つ以上の直接コストのubcategoryバケットでnullが発生する可能性を考慮に入れる必要があります。最後に、このクロス集計またはピボットを新しいテーブルEnctrUBCatPivotに送信する必要があります。

質問:上記のシナリオの正しいPIVOT構文は何ですか?UBCATEGORYエントリの数に応じて直接コストを削減したい場合、これらを反復処理してアカウントとUBCATEGORYでピボットするTSQLを作成するにはどうすればよいですか?これはすべて1つのsprocで実行されますか、それとも結果をテーブルに書き出すために複数のsprocに分割する必要がありますか?

これまでに書いたコードは次のとおりです。

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のアカウントとすべての直接コストを出力するという点で正常に機能します。ただし、ICCUDaysのピボットに列を追加するには、ACCOUNTのvwICCUDAYSに内部結合する必要があります。最終的なピボット列は、各UBCATEGORYmidのアカウント、ICCUDays、直接コストである必要があります。

私は合体構文にあまり精通していないため、列を追加するためにそれを変更する方法を識別できません。また、ICCUDaysを追加するために内部結合構文を追加する方法/場所もわかりません。

誰かが私を正しい方向に向けることができますか?ありがとう、シド

4

1 に答える 1

4

によってPIVOTに可能なすべての値を知る必要があります。したがって、動的SQLを使用しない限り、T-SQLでこれを直接行うことは困難であり、これは非常に迅速に問題になる可能性があります。おそらく、すべての行をプレゼンテーション層またはレポートライターに戻し、横向きにする方がよいでしょう。

すべてのUBCategory値を事前に知っている場合は、PIVOTの簡単な例を次に示します。結果の一部としてそのビューから来る列がない限り、それはかなり無関係に見えるので、私は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;

次に、「データを新しいテーブルに送信する」には、クエリを単純なSELECTの代わりにINSERT INTO...SELECTにすることができます。もちろん、これはちょっと役に立たないようです。なぜなら、その挿入ステートメントを書くためには、列の順序を知る必要があり(これはこのアプローチでは保証されません)、潜在的なUBCカテゴリごとに列をすでに入力している必要があるからです。とにかく価値があるので、これは非常に鶏肉と卵のようです。

于 2010-02-05T19:41:07.307 に答える