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