查询联结/链接/桥接表,列数据作为标题

时间:2014-06-05 21:50:36

标签: sql sql-server-2008 tsql pivot

我有一份专业清单(超过20个)

SpecialtyID  Description 
------------------------
1           Specialty1             
2           Specialty2
3           Specialty3

我有一份提供商列表(超过50个)

ProviderID  Name
------------------------
1           Tom             
2           Maria
3           Pat

每个提供商都可以拥有多个专业,每个专业可以拥有多个提供商 - 因此有多对多的关系。

我有一个名为SpecialtyProvider的联结/链接/桥接表,如果我只是使用以下查询查询链接表,我会得到下表。

SELECT SpecialtyID, ProviderID FROM SpecialtyProvider 

SpecialtyID  ProviderID
------------------------
1           1             
2           1
3           1
1           2             
2           2
3           3

我想做的是提取格式如下的数据:

SpecialtyID  ProviderID=1  ProviderID=2  ProviderID=3  ProviderID=x
-----------------------------------------------------------
1           true           true          NULL
2           true           true          NULL
3           true           NULL          true

一旦我可以正确格式化数据,我就会将其转储到ASP ListView中。

我不太清楚如何继续。我已经阅读了100篇关于PIVOT命令的不同变体的帖子,但是我没有集合功能,我还没有能够让任何其他示例/解决方案/分组有意义。

2 个答案:

答案 0 :(得分:2)

如果您需要在不使用聚合的情况下进行转动,通常只需使用MAX(您实际上只取一个值的MAX,即相同的值)。

select SpecialtyID, case when [1] is not null then 'true' end 'ProviderID=1', 
                    case when [2] is not null then 'true' end 'ProviderID=2', 
                    case when [3] is not null then 'true' end 'ProviderID=3'
from (
    select s.SpecialtyID, s.Description, sp.ProviderID
    from Specialty s 
    join SpecialtyProvider sp on sp.SpecialtyID = s.SpecialtyID
    ) x
pivot(  
    MAX(Description)
    for ProviderID in ([1],[2],[3])
      ) pvt

SQL Fiddle

但是,如果不使用PIVOT,也可以获得相同的结果:

select s.SpecialtyID, 
Max(case when sp.ProviderID = 1 then 'true' end) 'ProviderID=1',
Max(case when sp.ProviderID = 2 then 'true' end) 'ProviderID=2',
Max(case when sp.ProviderID = 3 then 'true' end) 'ProviderID=3'
from Specialty s 
join SpecialtyProvider sp on sp.SpecialtyID = s.SpecialtyID   
group by s.SpecialtyID

我发现这更容易阅读,也可能更快。

SQL Fiddle

尽管如此,您可能想重新考虑您的用户界面。具有50列宽的表将对于用户来说难以处理。过滤数据可能是有意义的,因此用户只能查看数据的特定部分。此外,如果您正在处理可变数量的提供程序,将所有数据提取到Web服务器并在ASP代码隐藏中处理它可能是有意义的。

答案 1 :(得分:1)

以下博客文章介绍了动态数据透视的概念,您无需指定列,以便解决提供程序的X因子。 http://beyondrelational.com/modules/2/blogs/70/posts/10840/dynamic-pivot-in-sql-server-2005.aspx

我更进一步,并打印出生成的SQL。以下是我提出来解决上述例子的问题。

IF (OBJECT_ID(N'dynamic_pivot', N'P') IS NOT NULL) 
DROP PROCEDURE dynamic_pivot
GO

CREATE PROCEDURE dynamic_pivot
(
  @select VARCHAR(2000)
, @PivotCol VARCHAR(100)
, @Summaries VARCHAR(100)
, @GenerateScript BIT = 1
)
AS
BEGIN
SET NOCOUNT ON ;
DECLARE @pivot VARCHAR(MAX)
  , @sql VARCHAR(MAX)
SELECT  @select = REPLACE(@select, 'SELECT ',
                          'SELECT ' + @PivotCol + ' AS pivot_col, ')


CREATE TABLE #pivot_columns
(
  pivot_column VARCHAR(100)
)

SELECT  @sql = 'SELECT DISTINCT pivot_col FROM (' + @select + ') AS t'

INSERT  INTO #pivot_columns
        EXEC ( @sql
            )

SELECT  @pivot = COALESCE(@pivot + ',', '') + '[' + pivot_column + ']'
FROM    #pivot_columns

SELECT  @sql = '
SELECT * 
FROM 
(
    ' + @select + '
) AS t 
PIVOT 
(
    ' + @Summaries + ' for pivot_col in (' + @pivot + ')
) AS p' 
 PRINT @sql
 EXEC(@sql) 
END
GO

EXEC [dbo].[dynamic_pivot] @select = 'SELECT SpecialtyID, 1 AS hasSpecialty FROM SpecialtyProvider', -- varchar(2000)
@PivotCol = 'ProviderID', -- varchar(100)
@Summaries = 'COUNT(hasSpecialty)' -- varchar(100)

SSMS中消息窗口中显示的结果查询如下:

SELECT * 
FROM 
(
    SELECT ProviderID AS pivot_col, SpecialtyID, 1 AS hasSpecialty FROM SpecialtyProvider
) AS t 
PIVOT 
(
    COUNT(hasSpecialty) for pivot_col in ([1],[2],[3])
) AS p

您可以对其进行修改,以提供所需的列名和值。