Как использовать PIVOT в хранимой процедуре SQL Server 2005, объединяющей два представления - PullRequest
2 голосов
/ 05 февраля 2010

Доброе утро,

У меня есть 2 представления: ICCUDays, который содержит одну запись на учетную запись с полями ACCOUNT и ICCUDays, ICCUEnctrSelectedRevCatsDirCost, которая содержит несколько записей на учетную запись с полями ACCOUNT, UBCATEGORY и DirectCost.

Моя цель: создать хранимую процедуру, которая выводит одну запись на АККАУНТ с ICCUDays и DirectCost от UBCATEGORY. Это будет кросс-таблица или сводная таблица, и она должна предусматривать возможность появления пустых значений в одном или нескольких сегментах подкатегорий прямых затрат. Наконец, эту кросс-таблицу или сводную таблицу необходимо отправить в новую таблицу EnctrUBCatPivot.

Вопросы: Каков правильный синтаксис PIVOT для вышеуказанного сценария? Учитывая, что я хочу вывести прямые затраты на сколько угодно записей UBCATEGORY, как мне написать TSQL для итерации по ним и поворота по аккаунту и UBCATEGORY? Все ли это выполняется в одном цикле, или его нужно разделить на несколько циклов, чтобы записать результаты в таблицу?

Вот код, который я написал до сих пор:

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. Однако мне нужно выполнить внутреннее соединение с vwICCUDAYS в ACCOUNT, чтобы добавить столбец в сводную таблицу для ICCUDays. В качестве окончательных сводных столбцов должны быть указаны Account, ICCUDays, Direct Cost для каждого UBCATEGORYmid.

Я не очень знаком с синтаксисом объединения и, следовательно, не могу понять, как его изменить, чтобы добавить дополнительные столбцы, и я не уверен, как / где добавить синтаксис внутреннего соединения для добавления ICCUDays.

Может ли кто-нибудь указать мне правильное направление? Спасибо, Sid

1 Ответ

4 голосов
/ 05 февраля 2010

Вам необходимо знать все возможные значения PIVOT. Так что это трудно сделать с помощью T-SQL напрямую, если вы не используете динамический 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. Конечно, это кажется бесполезным, потому что для написания этого оператора вставки необходимо знать порядок столбцов (что не гарантируется при таком подходе), и вы должны уже вставить столбцы для каждой потенциальной категории UBC значение в любом случае, так что это кажется очень курица и яйцо.

...