【问题标题】:Converting rows to Columns in SQL在 SQL 中将行转换为列
【发布时间】:2010-05-13 20:38:22
【问题描述】:

我有一个表格(实际上是一个视图,但将我的示例简化为一个表格),它为我提供了一些这样的数据

 CompanyName website
 Google         google.com
 Google         google.net
 Google         google.org
 Google         google.in
 Google         google.de
 Microsoft       Microsoft.com
 Microsoft       live.com
 Microsoft       bing.com
 Microsoft       hotmail.com

我希望将其转换为这样的结果

CompanyName website1      website2   website3   website 4   website5  website6 
----------- ------------- ---------- ---------- ----------- --------- --------
Google      google.com    google.net google.org google.in   google.de NULL
Microsoft   Microsoft.com live.com   bing.com   hotmail.com NULL      NULL

我已经研究过数据透视,但看起来记录(行值)不能是动态的(即只能是某些预定义的值)。

另外,如果网站超过6个,我想限制在前6个

动态枢轴是有道理的,但我必须将它纳入我的观点??有没有更简单的解决方案?

这里是 SQL 脚本

CREATE TABLE [dbo].[Company](

 [CompanyName] [varchar](50) NULL,
 [website] [varchar](50) NULL
) ON [PRIMARY]
GO

insert into company values ('Google','google.com')
insert into company values ('Google','google.net')
insert into company values ('Google','google.org')
insert into company values ('Google','google.in')
insert into company values ('Google','google.de')
insert into company values ('Microsoft','Microsoft.com')
insert into company values ('Microsoft','live.com')
insert into company values ('Microsoft','bing.com')
insert into company values ('Microsoft','hotmail.com')

编辑:我正在删除 ID,因为它是为简化而创建的。我想我不应该拥有它。对不起

【问题讨论】:

  • 你能说一下你为什么要这样吗?它是用于演示还是供其他程序使用?
  • 这是供其他程序使用的

标签: sql-server pivot


【解决方案1】:

试试这个:

DECLARE @Company table (
    [id] [int] NULL,
    [CompanyName] [varchar](15) NULL,
    [website] [varchar](15) NULL
) 

insert into @company values (1,'Google','google.com')
insert into @company values (2,'Google','google.net')
insert into @company values (3,'Google','google.org')
insert into @company values (4,'Google','google.in')
insert into @company values (5,'Google','google.de')
insert into @company values (6,'Microsoft','Microsoft.com')
insert into @company values (7,'Microsoft','live.com')
insert into @company values (8,'Microsoft','bing.com')
insert into @company values (9,'Microsoft','hotmail.com')

;WITH CompanyGrouped AS
(   SELECT
        *,ROW_NUMBER() OVER(PARTITION BY CompanyName ORDER BY CompanyName, id) AS ColumnNumber
        FROM @company
)
SELECT DISTINCT
    t.CompanyName
        ,t1.website AS website1,t2.website AS website2,t3.website AS website3, t4.website AS website4, t5.website AS website5, t6.website AS website6
    FROM @Company                      t
        LEFT OUTER JOIN CompanyGrouped t1 ON t.CompanyName=t1.CompanyName AND t1.ColumnNumber=1
        LEFT OUTER JOIN CompanyGrouped t2 ON t.CompanyName=t2.CompanyName AND t2.ColumnNumber=2
        LEFT OUTER JOIN CompanyGrouped t3 ON t.CompanyName=t3.CompanyName AND t3.ColumnNumber=3
        LEFT OUTER JOIN CompanyGrouped t4 ON t.CompanyName=t4.CompanyName AND t4.ColumnNumber=4
        LEFT OUTER JOIN CompanyGrouped t5 ON t.CompanyName=t5.CompanyName AND t5.ColumnNumber=5
        LEFT OUTER JOIN CompanyGrouped t6 ON t.CompanyName=t6.CompanyName AND t6.ColumnNumber=6

输出:

CompanyName website1      website2   website3   website4    website5  website6
----------- ------------- ---------- ---------- ----------- --------- --------
Google      google.com    google.net google.org google.in   google.de NULL
Microsoft   Microsoft.com live.com   bing.com   hotmail.com NULL      NULL

(2 row(s) affected)

【讨论】:

    【解决方案2】:

    如果您使用的是 SQL Server 2005+,您可以执行以下操作:

    With NumberedSites As
        (
        Select CompanyName, Website
            , ROW_NUMBER() OVER( PARTITION BY CompanyName ORDER BY Id ) As Num
        From Table
        )
    Select CompanyName
        , Min( Case When Num = 1 Then Website End ) As Website1
        , Min( Case When Num = 2 Then Website End ) As Website2
        , Min( Case When Num = 3 Then Website End ) As Website3
        , Min( Case When Num = 4 Then Website End ) As Website4
        , Min( Case When Num = 5 Then Website End ) As Website5
        , Min( Case When Num = 6 Then Website End ) As Website6
    From NumberedSites
    Where Num <= 6
    Group By CompanyName
    

    现在,这个解决方案显然不是动态的,它假设有六列(包括公司名称在内的七列)。如果你想要一组动态的列,唯一的方法是使用一些动态的 SQL 代码。相反,如果您需要动态交叉表,我建议您在中间层或报告工具中进行。

    【讨论】:

      【解决方案3】:

      我不得不为我的工作处理一份类似的报告,但我从不同的方向着手。我编写(模仿)了一个 SQL CLR 自定义聚合,以将网站列表汇总为逗号分隔的字符串。

      例如:

      --load the temp table named Company from your example
      --then run this query
      SELECT CompanyName, StringUtil.Concat(Website) AS WebSites FROM Company
      
      --outputs:
      
      CompanyName Websites
      ----------- ---------------------------------------------------
      Google      google.com, google.net, google.org, google.in, google.de
      Microsoft   microsoft.com, live.com, bing.com, hotmail.com
      
      (2 row(s) affected)
      

      构建/安装/使用 CLR 自定义聚合的代码和说明随 SQL Server(2005 及更高版本)提供,但通常不安装。 文档位于 MSDN http://msdn.microsoft.com/en-US/library/ms161551(v=SQL.90).aspx

      【讨论】:

      • 哦,是的,还有,CLR 自定义聚合的速度非常快。比使用光标快 10000 倍
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      • 2013-10-01
      • 1970-01-01
      • 2020-04-28
      相关资源
      最近更新 更多