【问题标题】:SQL Server columns as rows in result of querySQL Server 列作为查询结果中的行
【发布时间】:2014-10-15 01:12:24
【问题描述】:

如何获取一些列被查询并表现为行的表?

源表

ID | Name | Funct    | Phone1 | Phone2 | Phone3
1  | John | boss     | 112233 | 114455 | 117788
2  | Jane | manager  | NULL   | NULL   | 221111
3  | Tony | merchant | 441100 | 442222 | NULL

想要的结果

ID | Name | Funct    | Phone  | Ord
1  | John | boss     | 112233 | 1
1  | John | boss     | 114455 | 2
1  | John | boss     | 117788 | 3
2  | Jane | manager  | 221111 | 3
3  | Tony | merchant | 441100 | 1
3  | Tony | merchant | 442222 | 2

Ord 是一列,其中是原始列的订单号 (Phone1...Phone3)

已编辑:

好的,UNION 当电话号码在单独的列中时会很好,但如果源在后面(一列中的所有数字)怎么办?:

ID | Name | Funct    | Phones
1  | John | boss     | 112233,114455,117788
2  | Jane | manager  | 221111
3  | Tony | merchant | 441100,442222

我明白了,Ord 的列是无意义的(所以在这种情况下忽略它),但是如何将数字拆分为分隔行?

【问题讨论】:

  • 如果您知道每个客户有 3 部手机,那么 UNION ALL 是一个不错的选择

标签: sql sql-server querying


【解决方案1】:

最简单的方法是使用union all

select id, name, funct, phone1 as phone, 1 as ord
from source
where phone1 is not null
union all
select id, name, funct, phone2 as phone, 2 as ord
from source
where phone2 is not null
union all
select id, name, funct, phone3 as phone, 3 as ord
from source
where phone3 is not null;

您可以使用cross apply 将其写为:

select so.*
from source s cross apply
     (select s.id, s.name, s.funct, s.phone1 as phone, 1 as ord union all
      select s.id, s.name, s.funct, s.phone2 as phone, 2 as ord union all
      select s.id, s.name, s.funct, s.phone3 as phone, 3 as ord
     ) so
where phone is not null;

还有使用unpivotcross join/case的方法。

【讨论】:

  • 好的,还有另一种解决方案吗?使用 cross aplly 或类似的东西?
【解决方案2】:

请看下面的答案,

Declare @table table
(ID int, Name varchar(100),Funct varchar(100),Phones varchar(400))

Insert into @table Values 
(1,'John','boss','112233,114455,117788'),
(2,'Jane','manager','221111' ),
(3,'Tony','merchant','441100,442222')

Select * from @table

结果:

代码:

Declare @tableDest table
([ID] int, [name] varchar(100),[Phones] varchar(400))

Declare @max_len int,
        @count int = 1

Set @max_len =  (Select max(Len(Phones) - len(Replace(Phones,',','')) + 1)
                From    @table)

While @count <= @max_len
begin
    Insert  into @tableDest
    Select  id,Name,
            SUBSTRING(Phones,1,charindex(',',Phones)-1)
    from    @table
    Where   charindex(',',Phones) > 0
    union   
    Select  id,Name,Phones
    from    @table
    Where   charindex(',',Phones) = 0

    Delete from @table
    Where   charindex(',',Phones) = 0

    Update  @table
    Set     Phones =  SUBSTRING(Phones,charindex(',',Phones)+1,len(Phones))
    Where   charindex(',',Phones) > 0

    Set     @count = @count + 1
End
------------------------------------------
Select  * 
from    @tableDest
Order By ID
------------------------------------------

最终结果:

【讨论】:

  • 非常好的 Jithin,感谢您提供有用的代码,但我已要求将其用于查询(选择、查看...)。如何在查询中使用它?使用UDF...或者...有没有另一种方法可以在不插入变量表的情况下将循环写入选择?
【解决方案3】:
       SELECT CONCAT(
      'CREATE TABLE New_Table (',GROUP_CONCAT(
                            DISTINCT CONCAT(Name, ' VARCHAR(50)')
                            SEPARATOR ','),');')
      FROM
      Previous_Table
      INTO @sql;
      PREPARE stmt FROM @sql;
      EXECUTE stmt;

此查询根据另一个表的列值在一个表中生成一行。这可能对你有帮助

【讨论】:

    猜你喜欢
    • 2016-05-24
    • 1970-01-01
    • 2015-03-15
    • 1970-01-01
    • 2017-04-05
    • 1970-01-01
    • 2016-05-03
    • 2014-06-06
    • 1970-01-01
    相关资源
    最近更新 更多