【问题标题】:Rotate/pivot 1000 columns to rows将 1000 列旋转/旋转为行
【发布时间】:2012-09-16 01:41:22
【问题描述】:

我继承了一个数据库,我需要从中提取当前按行排列的列中的数据。检索数据的查询是:

select distinct 
    LIMSNo, p250.*, p500.*, p750.*, p1000.* 
from 
    results as r
    inner join Points250 as p250 
    on r.resultsid = p250.resultsid and p250.channel = 1
    inner join Points500 as p500 
    on r.resultsid = p500.resultsid and p500.channel = 1
    inner join Points750 as p750 
    on r.resultsid = p750.resultsid and p750.channel = 1
    inner join Points1000 as p1000 
    on r.resultsid = p1000.resultsid and p1000.channel = 1
where 
    r.limsno between '120053698' and '120053704'

产生

LIMSNo           P0001              P0002              P0003   ...     P1000  
120053698        251.6667           302.0196           302.2353        305.9608
120053699        291.6667           342.6545           347.9635        353.6236
120053700        243.3333           298.3206           296.7235        299.5342
120053701        308.3333           365.8397           365.4071        368.3206
120053702        315                363.4153           366.6052        373.1695

注意有 1000 列 (P0001...P1000)

我想旋转/旋转数据以便得到这个输出:

        120053698        120053699        120053700        120053701        120053702 
P0001   251.6667         291.6667         243.3333         308.3333         315
P0002   302.0196         342.6545         298.3206         365.8397         363.4153
...
P1000   305.9608         353.6236         299.5342         368.3206         373.1695

如何构建 SQL 查询?数据库是 SQL 2000。

我已经尝试了多种方法来解决这个问题。我最近的尝试是:

create table #tempCols
(
    ColName nchar(15)
)

insert into #tempCols
select 
    column_name 
from 
    information_schema.columns
where 
    table_name = 'Points250' 
and column_name like 'P%'

insert into #tempCols
select 
    column_name 
from 
    information_schema.columns
where 
    table_name = 'Points500' 
and column_name like 'P%'

insert into #tempCols
select 
    column_name 
from 
    information_schema.columns
where 
    table_name = 'Points750' 
and column_name like 'P%'

insert into #tempCols
select 
    column_name 
from 
    information_schema.columns
where 
    table_name = 'Points1000' 
and column_name like 'P%'

create table #LIMSList
(
    LIMSNumber nchar(9)
)
insert into #LIMSList
select LimsNo from results
where LimsNo between '100030460' and '100030500'

declare @colList varchar(max)
select @colList = COALESCE(@colList + ',' ,'') + ColName from #tempCols

declare @command varchar(max)
set @command = 
'
    select LimsNo, Point, Data
    from (
        select LimsNo, p250.*, p500.*, p750.*, p1000.* 
        from 
            results as r
            inner join Points250 as p250 
            on r.resultsid = p250.resultsid and p250.channel = 1
            inner join Points500 as p500 
            on r.resultsid = p500.resultsid and p500.channel = 1
            inner join Points750 as p750 
            on r.resultsid = p750.resultsid and p750.channel = 1
            inner join Points1000 as p1000 
            on r.resultsid = p1000.resultsid and p1000.channel = 1
        where 
            limsno in (select LimsNo from #LIMSList)) d
            unpivot (Data for Point in (' + @colList + ')) as unpvt
'

print @command

exec(@command)

drop table #tempCols
drop table #LIMSList

但我得到的错误是:

Msg 8156, Level 16, State 1, Line 1
The column 'ResultsID' was specified multiple times for 'd'.
Msg 8156, Level 16, State 1, Line 1
The column 'ResultsID' was specified multiple times for 'unpvt'.

【问题讨论】:

  • 我尝试了很多方法。查看我的编辑以了解我最近的尝试。
  • 您需要只做一次,还是定期做一次?如果只有一次,您可以将其全部放在一个 Excel 工作表中,复制整个数据集,然后使用 paste special | 将其粘贴到另一个工作表中。 transpose.
  • 我怀疑它会不止一次,虽然不是定期。感谢 Excel 的建议。

标签: sql sql-server sql-server-2000 pivot unpivot


【解决方案1】:

由于 SQL Server 2000 没有 UNPIVOTPIVOT 运算符,因此您必须将 UNION ALL 用于 UNPIVOT,然后将 CASE 语句用于 PIVOT。这是一个应该可行的动态解决方案:

DECLARE @query  AS NVARCHAR(MAX),
  @rowCount as int = 1,
  @unpivotCount as int = 0,
  @pivotCount as int,
  @unRow as varchar(10) = '',
  @pivotRow as varchar(10) = ''

select c.Name col
into #colsUnpivot
from sys.columns as C
where C.object_id = object_id('yourtable') and
    C.name LIKE 'P%'

set @unpivotCount = (select count(*) from #colsUnpivot)

-- unpivot the data
while @rowCount <= @unpivotCount 
  begin
    set @unRow = (select Top 1 col from #colsUnpivot)

    set @query =' insert into unpivotData (LIMSNo, Val, Col)
                  select LIMSNo, ' + @unRow + ' as val, ''' 
                    + @unRow  + ''' as col
                  from yourtable'

     exec(@query)

     delete from #colsUnpivot where col = @unRow

     if @rowCount <= @unpivotCount 
        set @rowCount = @rowCount + 1
  end

--select * 
--from unpivotData

-- pivot the data 
select distinct LIMSNo
into #colsPivot
from yourtable

set @pivotCount= (select COUNT(*) from #colsPivot) 
-- reset rowcount
set @rowCount = 1
set @query = ''

---- create the CASE string
while @rowCount <= @pivotCount
    begin
        set @pivotRow = (select Top 1 LIMSNo from #colsPivot)

        set @query = @query + ', max(case when LIMSNo = ' + @pivotRow + ' then val end) as ''' + @pivotRow + ''''

        delete from #colsPivot where LIMSNo = @pivotRow

        if @rowCount <= @pivotCount
            begin
                set @rowCount = @rowCount + 1
                print @rowCount
            end
    end

-- add the rest of the SQL Statement
set @query = 'SELECT col ' + @query + ' from dbo.unpivotData group by col'

exec(@query)

delete from dbo.unpivotData

drop table #colsUnpivot
drop table #colspivot

我创建了一个名为UnpivotData 的表来保存用于PIVOT 进程的数据。

SQL Fiddle with Demo

【讨论】:

【解决方案2】:

pivot 和 unpivot 运算符在 SQL Server 2000 中不可用。因此您必须使用其他技术对数据进行旋转和取消旋转。

我列出了 unpivot 和 pivot 的静态方法,希望您可以根据需要将其转换为动态解决方案。

假设您已将查询的数据插入到表中,您可以使用 UNION ALL 取消透视数据并将其插入到临时表中。

SELECT 
*
INTO dbo.temp
FROM 
(
SELECT LIMSNo, P0001 AS [Point],'P0001' AS [ColName] FROM dbo.myTable
UNION ALL 
SELECT LIMSNo, P0002 AS [Point],'P0002' AS [ColName] FROM dbo.myTable
UNION ALL 
SELECT LIMSNo, P0003 AS [Point],'P0003' AS [ColName] FROM dbo.myTable
UNION ALL 
SELECT LIMSNo, P0004 AS [Point],'P0004' AS [ColName] FROM dbo.myTable
....
....
UNION ALL 
SELECT LIMSNo, P1000 AS [Point],'P1000' AS [ColName] FROM dbo.myTable
) AS t

然后您可以再次旋转数据

SELECT 
ColName
,MAX(CASE LIMSNo WHEN '120053698' THEN [Point] ELSE NULL END ) AS [120053698]
,MAX(CASE LIMSNo WHEN '120053699' THEN [Point] ELSE NULL END ) AS [120053699]
,MAX(CASE LIMSNo WHEN '120053700' THEN [Point] ELSE NULL END ) AS [120053700]
....
....
,MAX(CASE LIMSNo WHEN '120053704' THEN [Point] ELSE NULL END ) AS [120053704]

FROM dbo.temp
GROUP BY ColName

【讨论】:

  • 谢谢,@ClearLogic,我会尝试为您的查询开发一个动态版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-08
  • 2022-01-20
  • 2016-06-16
  • 2012-09-29
  • 2018-02-18
相关资源
最近更新 更多