TSQL表转换字段=>列

时间:2010-08-27 17:59:41

标签: sql sql-server tsql pivot

我有以下表格布局。每个行值始终是唯一的。永远不会有多个相同的Id,Name和Line实例。

Id Name Line
1  A    Z
2  B    Y
3  C    X
3  C    W
4  D    W

我想查询数据,以便Line字段成为一列。如果该值存在,则在字段数据中应用1,否则为0.例如

Id Name Z Y X W
1  A    1 0 0 0
2  B    0 1 0 0
3  C    0 0 1 1
4  D    0 0 0 1

字段名称W,X,Y,Z只是字段值的示例,因此我无法应用运算符来明确检查,例如,“X”,“Y”或“Z”。这些可以随时改变,并且不限于一组有价值的值。结果集中的列名称应将唯一字段值反映为列。

知道我怎么能做到这一点吗?

7 个答案:

答案 0 :(得分:6)

这是一个标准的数据透视查询。

如果1表示布尔指示符 - 请使用:

  SELECT t.id,
         t.name,
         MAX(CASE WHEN t.line = 'Z' THEN 1 ELSE 0 END) AS Z,
         MAX(CASE WHEN t.line = 'Y' THEN 1 ELSE 0 END) AS Y,
         MAX(CASE WHEN t.line = 'X' THEN 1 ELSE 0 END) AS X,
         MAX(CASE WHEN t.line = 'W' THEN 1 ELSE 0 END) AS W
    FROM TABLE t
GROUP BY t.id, t.name

如果1表示具有该组值的记录数,请使用:

  SELECT t.id,
         t.name,
         SUM(CASE WHEN t.line = 'Z' THEN 1 ELSE 0 END) AS Z,
         SUM(CASE WHEN t.line = 'Y' THEN 1 ELSE 0 END) AS Y,
         SUM(CASE WHEN t.line = 'X' THEN 1 ELSE 0 END) AS X,
         SUM(CASE WHEN t.line = 'W' THEN 1 ELSE 0 END) AS W
    FROM TABLE t
GROUP BY t.id, t.name

答案 1 :(得分:2)

更新后的

已修改

SQL Server不支持动态透视。

要执行此操作,您可以使用动态SQL沿以下行生成查询。

SELECT 
       Id ,Name, 
       ISNULL(MAX(CASE WHEN Line='Z' THEN 1 END),0) AS Z,
       ISNULL(MAX(CASE WHEN Line='Y' THEN 1 END),0) AS Y,
       ISNULL(MAX(CASE WHEN Line='X' THEN 1 END),0) AS X,
       ISNULL(MAX(CASE WHEN Line='W' THEN 1 END),0) AS W
FROM T
 GROUP BY Id ,Name

或者我已经阅读但未实际尝试过的另一种方法是利用Access Transform函数,通过设置一个Access数据库,其链接表指向SQL Server表,然后从SQL Server查询Access数据库!

答案 2 :(得分:2)

这是动态版

测试表

create table #test(id int,name char(1),line char(1))

insert #test values(1 , 'A','Z')
insert #test values(2 , 'B','Y')
insert #test values(3 , 'C','X')
insert #test values(4 , 'C','W')
insert #test values(5 , 'D','W')
insert #test values(5 , 'D','W')
insert #test values(5 , 'D','P')

现在运行此

declare @names nvarchar(4000)

SELECT @names =''
  SELECT  @names    = @names +   line +', '  
    FROM (SELECT distinct  line from #test) x

SELECT @names = LEFT(@names,(LEN(@names) -1))

exec('
SELECT *
 FROM(
SELECT DISTINCT Id, Name,Line
FROM #test
    ) AS pivTemp
PIVOT
(   COUNT(Line)
    FOR Line IN (' + @names +' )
) AS pivTable ')

现在向表中添加一行并再次运行上面的查询,您将看到B

insert #test values(5 , 'D','B')

警告:当然,动态SQL的所有问题都适用,如果你可以使用sp_executeSQL,但由于参数在查询中没有使用,所以确实没有意义

答案 3 :(得分:1)

假设您可以枚举Line的有限数量的值:

declare @MyTable table (
    Id int,
    Name char(1),
    Line char(1)
)

insert into @MyTable
    (Id, Name, Line)
    select 1,'A','Z'
    union all
    select 2,'B','Y'
    union all
    select 3,'C','X'
    union all
    select 3,'C','W'
    union all
    select 4,'D','W'

SELECT Id, Name, Z, Y, X, W
    FROM (SELECT Id, Name, Line
            FROM @MyTable) up
    PIVOT (count(Line) FOR Line IN (Z, Y, X, W)) AS pvt
    ORDER BY Id

答案 4 :(得分:0)

在使用SQL Server时,您可以使用用于此目的的PIVOT运算符。

答案 5 :(得分:0)

如果您正在为SQL Server Reporting Services(SSRS)报告执行此操作,或者可能切换为使用一个,则立即停止并将Matrix控件抛出到您的报告中。噗!你完成了!随着您的数据的转变而感到高兴。

答案 6 :(得分:0)

这是一种相当奇特的方法(使用来自旧Northwind数据库的示例数据)。它改编自版本here,由于DBCC RENAMECOLUMN的弃用以及PIVOT作为关键字的添加而不再有效。

set nocount on 
create table Sales ( 
  AccountCode char(5), 
  Category varchar(10), 
  Amount decimal(8,2) 
) 
--Populate table with sample data 
insert into Sales 
select customerID, 'Emp'+CAST(EmployeeID as char), sum(Freight) 
from Northwind.dbo.orders 
group by customerID, EmployeeID 
create unique clustered index Sales_AC_C 
on Sales(AccountCode,Category) 
--Create table to hold data column names and positions 
select A.Category, 
       count(distinct B.Category) AS Position 
into #columns 
from Sales A join Sales B 
on A.Category >= B.Category 
group by A.Category 
create unique clustered index #columns_P on #columns(Position) 
create unique index #columns_C on #columns(Category) 
--Generate first column of Pivot table 
select distinct AccountCode into Pivoted from Sales 
--Find number of data columns to be added to Pivoted table 
declare @datacols int 
select @datacols = max(Position) from #columns 
--Add data columns one by one in the correct order 
declare @i int 
set @i = 0 
while @i < @datacols begin 
  set @i = @i + 1 
--Add next data column to Pivoted table 
  select P.*, isnull(( 
    select Amount 
    from Sales S join #columns C 
    on C.Position = @i 
    and C.Category = S.Category 
    where P.AccountCode = S.AccountCode),0) AS X 
  into PivotedAugmented 
  from Pivoted P 
--Name new data column correctly 
  declare @c sysname 
  select @c = Category 
  from #columns 
  where Position = @i 
  exec sp_rename '[dbo].[PivotedAugmented].[X]', @c, 'COLUMN'
--Replace Pivoted table with new table 
  drop table Pivoted 
  select * into Pivoted from PivotedAugmented 
  drop table PivotedAugmented 
end 
select * from Pivoted 
go 
drop table Pivoted 
drop table #columns 
drop table Sales