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

Sql server 我需要使用pivot将SQL Server行展平为列,sql-server,tsql,pivot,Sql Server,Tsql,Pivot,我尝试使用SQLServerPivot已经有一段时间了,但我似乎没有正确地使用它。我已经读了很多答案,但不明白pivot是如何工作的 我正在写一个存储过程。我有表1(作为TVP接收),需要使它看起来像表2() 重要提示:Table1.valueTypeID中的值不能硬编码到逻辑中,因为它们总是可以更改的。因此,逻辑必须是超动态的 请参阅下面的代码。枢轴位于存储过程的末尾 -- Create date: 12/10/2013 -- Descripti

我尝试使用SQLServerPivot已经有一段时间了,但我似乎没有正确地使用它。我已经读了很多答案,但不明白pivot是如何工作的

我正在写一个存储过程。我有表1(作为TVP接收),需要使它看起来像表2()

重要提示: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

您需要在您的案例中使用dynamic pivot。试试下面的方法

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

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

在许多情况下,客户端比数据库引擎更擅长数据透视。例如,SQLServerReportingServices可以通过矩阵控件轻松实现这一点。类似地,如果在Asp.Net中编写网页,可以快速遍历记录集,将数据传递到新的数据表示形式(同时收集唯一值),然后在一次遍历中,新的数据对象吐出HTML以呈现结果

如果可能的话,让您的客户机代替服务器进行数据透视

更新:

如果您真的想在动态SQL中使用表变量,可以在SQLServer2008及更高版本中使用。下面是一个示例脚本:

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;

你尝试过什么?@GordonLinoff我使用游标动态构建新表,但是每个人都说游标很昂贵,应该避免使用。对此有何看法?游标通常很昂贵,应该避免使用,尤其是当查询可以完成这项工作时。在MS SQL文档中查找
pivot
以了解其工作原理。我尝试使用您的解决方案,但我的C#server抛出了一个奇怪的错误,即“必须声明表变量@contactsPropsForReturnFilter”。我已经用存储过程的代码更新了我的问题。枢轴(您的代码,已修改)位于存储过程的末尾。你能看一看吗?开始工作了!必须将@contactsPropsForReturnFiltered表变量更改为#contactsPropsForReturnFiltered临时表。据我所知,不可能执行引用@tableVariable的@query字符串,因为@tableVariable不在其作用域内。令人惊叹的。爱知识,这是不对的。在SQL 2008及更高版本中,可以在动态SQL中使用表值参数。有关更多信息,请参阅我的更新答案。数据永远不会返回到web客户端。在这种情况下,它将返回到IIS服务器上运行的c#应用程序。据我所知,你是说最好在c#app上重新组织数据,而不是在SQL server上。你能给出这种观点的原因吗?@quelquecosa我建议这样做有两个原因:1)这是一个演示问题,2)SQL Server不做自动数据透视(它不能自动从数据中发现列名,就像MS Access在数据透视查询中所做的那样)。由于在C#中进行数据透视并不是那么困难,我的建议是使用一种工具,以避免动态SQL的陷阱和缺点。