我需要使用pivot将SQL Server行展平为列

时间:2013-12-12 21:32:44

标签: sql-server tsql pivot

我已经尝试了一段时间来使用SQL Server数据透视表,但我似乎并没有把它做对。我已经阅读了一堆SO答案,但不明白枢轴是如何工作的。

我正在编写存储过程。我有表1(作为TVP收到),需要看起来像表2(see this image for tables)。

重要说明:Table1.valueTypeID中的值无法硬编码到逻辑中,因为它们总是可以更改。因此,逻辑必须是超级动态的。

请参阅下面的代码。枢轴位于存储过程的末尾。

            -- Create date: 12/10/2013
            -- Description: select all the contacts associated with received accountPassport
            -- =============================================
            ALTER PROCEDURE [dbo].[selectContactsPropsByAccountPassport] 
                -- Add the parameters for the stored procedure here
                @accountPassport int, 
                @valueTypeFiltersTVP valueTypeFiltersTVP READONLY
            AS
            BEGIN
                -- SET NOCOUNT ON added to prevent extra result sets from
                -- interfering with SELECT statements.
                SET NOCOUNT ON;

                -- Insert statements for procedure here
                DECLARE @accountID int;
                DECLARE @contactsAppAccountPassport int;
                DECLARE @searchResults TABLE
                    (
                        resultContactID int
                    );
                DECLARE @resultContactID int;

                DECLARE @contactsPropsForReturn TABLE
                    (
                        contactID int,
                        valueTypeID int,
                        value varchar(max)
                    );

                create table #contactsPropsForReturnFiltered(contactID int,valueTypeID int, value varchar(max))

                /*
                DECLARE #contactsPropsForReturnFiltered TABLE 
                    (
                        contactID int,
                        valueTypeID int,
                        value varchar(max)
                    );
                */

            --2. get @contactsAppAccountPassport associated with recieved @accountPassport
                -- go into dbo.accounts and get the @accountID associated with this @accountPassport
                SELECT
                    @accountID = ID
                FROM
                    dbo.accounts
                WHERE
                    passport = @accountPassport

                -- go into dbo.accountsProps and get the value (@contactsAppAccountPassport) where valueType=42 and accountID = @accountID
                SELECT
                    @contactsAppAccountPassport = value
                FROM
                    dbo.accountsProps
                WHERE
                    (valueTypeID=42) AND (accountID = @accountID)

            --3. get all the contact ID's from dbo.contacts associated with @contactsAppAccountPassport
                INSERT INTO
                    @searchResults
                SELECT
                    ID
                FROM
                    dbo.contacts
                WHERE
                    contactsAppAccountPassport = @contactsAppAccountPassport

            --4. Get the props of all contact ID's from 3. 

                --start for each loop....our looping object is @resultContactID row. if there are more rows, we keep looping.
                DECLARE searchCursor CURSOR FOR
                    SELECT
                        resultContactID
                    FROM
                        @searchResults

                    OPEN searchCursor

                        FETCH NEXT FROM searchCursor INTO @resultContactID

                        WHILE (@@FETCH_STATUS=0)
                        BEGIN   
                            INSERT INTO
                                @contactsPropsForReturn
                            SELECT
                                contactID,
                                valueTypeID,
                                value
                            FROM
                                dbo.contactsProps
                            WHERE
                                contactID = @resultContactID
                            FETCH NEXT FROM searchCursor INTO @resultContactID
                        END --end of WHILE loop

                    --end of cursor (both CLOSE and DEALLOCATE necessary)
                    CLOSE searchCursor
                    DEALLOCATE searchCursor

                    -- select and return only the props that match with the requested props 
                    -- (we don't want to return all the props, only the ones requested)
                    INSERT INTO
                        #contactsPropsForReturnFiltered
                    SELECT
                        p.contactID,
                        p.valueTypeID,
                        p.value
                    FROM
                        @contactsPropsForReturn as p
                    INNER JOIN
                        @valueTypeFiltersTVP as f
                    ON
                        p.valueTypeID = f.valueTypeID



                    DECLARE @cols AS NVARCHAR(MAX),
                    @query  AS NVARCHAR(MAX);

                    SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(ValueTypeId) 
                        FROM #contactsPropsForReturnFiltered 
                        FOR XML PATH(''), TYPE
                        ).value('.', 'NVARCHAR(MAX)') 
                    ,1,1,'');

            set @query = 'SELECT contactid, ' + @cols + ' from 
                        (
                            select contactid
                                , Value
                               ,ValueTypeId
                            from #contactsPropsForReturnFiltered
                       ) x
                        pivot 
                        (
                             min(Value)
                            for ValueTypeId in (' + @cols + ')
                        ) p ';

            execute(@query);

            END

2 个答案:

答案 0 :(得分:2)

您需要在案例中使用动态数据透视。请尝试以下

create table table1
(
    contactid int,
    ValueTypeId int,
    Value varchar(100)
);

insert into table1 values (56064, 40, 'Issac');
insert into table1 values (56064, 34, '(123)456-7890');
insert into table1 values (56065, 40, 'Lola');
insert into table1 values (56065, 34, '(123)456-7832');
insert into table1 values (56068, 40, 'Mike');
insert into table1 values (56068, 41, 'Gonzalez');
insert into table1 values (56068, 34, '(123)456-7891');


DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX);

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(ValueTypeId) 
            FROM table1 
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'');

set @query = 'SELECT contactid, ' + @cols + ' from 
            (
                select contactid
                    , Value
                   ,ValueTypeId
                from table1
           ) x
            pivot 
            (
                 min(Value)
                for ValueTypeId in (' + @cols + ')
            ) p ';


execute(@query);

drop table table1

答案 1 :(得分:0)

为什么需要以这种方式呈现数据?

在许多情况下,客户端比数据库引擎更好地进行数据透视。例如,SQL Server Reporting Services可以使用矩阵控件轻松完成此操作。同样,如果您在Asp.Net中对网页进行编码,则可以快速运行记录集以将数据传递到新的数据表示形式(同时收集唯一值),然后一次性通过新数据对象吐出HTML来呈现结果。

如果可能,请让您的客户端进行透视而不是服务器。

<强>更新

如果你真的想在动态SQL中使用表变量,你可以在SQL Server 2008及更高版本中使用。这是一个示例脚本:

USE tempdb
GO
CREATE TYPE IDList AS TABLE (
    ID int
);
GO
DECLARE @SQL nvarchar(max);
SET @SQL = 'SELECT * FROM @TransactionIDs WHERE ID >= 4;'
DECLARE @TransactionIDs IDLIst;
INSERT @TransactionIDs VALUES (1), (2), (4), (8), (16);
EXEC sp_executesql @SQL, N'@TransactionIDs IDList READONLY', @TransactionIDs;
GO
DROP TYPE IDList;