[英]Stored procedure to do a two-level pivot
我正在尝试在Sybase
Adaptive Server Anywhere
中创建一个存储过程,该存储过程将完成表的双重操作。 我将首先用一些图像概述我要完成的工作。
问题
这是表中的原始数据; 在我下面向下发布的示例代码中,这是临时表#t1:
数据rownr
的第一级包括对rownr
列进行分组和对列col
rownr
,将结果表放入临时表#t2中:
到目前为止,我已经发布了下面的代码。
这是我正在努力的部分。 现在,我需要对ObjectId
列上的表#t2分组进行透视,并为该分组中的行数复制列Operation
和Code
,以生成表#t3。 因此,我给出的示例的结果将如下所示:
因为要复制两列(“ Operation
和Code
),所以结果表中的列数应等于2乘以分组中具有最大行数的行数。 如示例所示, 小于分组行的最大数目的分组将被填充为空值。
编码
这是我的代码,用于创建前两个表#t1和#t2:
begin
create table #t1(rownr int, col nvarchar(15), val nvarchar(300));
insert into #t1 values(1, 'ObjectId', 'A');
insert into #t1 values(1, 'Operation', 'Op1');
insert into #t1 values(1, 'Code', '101');
insert into #t1 values(2, 'ObjectId', 'A');
insert into #t1 values(2, 'Operation', 'Op2');
insert into #t1 values(2, 'Code', '102');
insert into #t1 values(3, 'ObjectId', 'B');
insert into #t1 values(3, 'Operation', 'Op3');
insert into #t1 values(3, 'Code', '103');
insert into #t1 values(4, 'ObjectId', 'B');
insert into #t1 values(4, 'Operation', 'Op4');
insert into #t1 values(4, 'Code', '104');
insert into #t1 values(5, 'ObjectId', 'B');
insert into #t1 values(5, 'Operation', 'Op5');
insert into #t1 values(5, 'Code', '105');
-- Create t2
select
rownr,
Max(case when col = 'ObjectId' then val end) as ObjectId,
Max(case when col = 'Operation' then val end) as Operation,
Max(case when col = 'Code' then val end) as Code
into #t2
from #t1
group by rownr
order by rownr, ObjectId;
select * from #t2;
-- Create #t3 <--- This is where I need help
end
记笔记
请注意,我试图解决这一对Sybase
Adaptive Server Anywhere
不具有一个pivot
声明像Sql Server
呢,所以使用的解决方案pivot
声明绝不会帮我。
您需要在单个临时表中的每组A,B等及其ObjectId,对ObjectID的排序整数为1,2,3,4,而与op的字符串值无关。
有了IDENTITY,获得这样一个有序整数通常很容易,但是您并不想全部都想要它,而是希望每个A,B,C等子集都需要它。
因此,如果您可以对每个ObjectId值(A,B,C等)运行Cursor并将这些对象的整数排序操作放入临时表中,则可以轻松进行多个外部联接的数据透视。
所以:创建表#l(Id NUMERIC(8)IDENTITY,op VARCHAR(30),obj VARCHAR(300))去
set identity_insert #l on
在objectIds上获取一个游标,然后像这样循环:
select Id = IDENTITY(8)
, t2.val op
, t1.val obj
into
existing table
#l
from #t1 t1, #t1 t2
where t1.col = 'ObjectId'
and t1.val = 'A' -- this would be the cursors value
and t1.rownr = t2.rownr
and t2.col = 'Operation'
然后,您会发现#l可以很好地与多个外部对象一起旋转,因为您将拥有一个像这样的表:
select * from #l order by 3,1
Id op obj
----------- ------ -----
1 Op1 A
2 Op2 A
1 Op3 B
2 Op4 B
3 Op5 B
以防万一这对其他人有帮助,下面是我最终想出的代码,以完成所需的双重工作:
begin
DECLARE @nr_of_columns smallint;
DECLARE @qry long varchar;
DECLARE @i SMALLINT;
DECLARE @createTable nvarchar(1000);
create table #t1(rownr int, col nvarchar(15), val nvarchar(300));
insert into #t1 values(1, 'ObjectId', 'A');
insert into #t1 values(1, 'Operation', 'Op1');
insert into #t1 values(1, 'Code', '101');
insert into #t1 values(2, 'ObjectId', 'A');
insert into #t1 values(2, 'Operation', 'Op2');
insert into #t1 values(2, 'Code', '102');
insert into #t1 values(3, 'ObjectId', 'B');
insert into #t1 values(3, 'Operation', 'Op3');
insert into #t1 values(3, 'Code', '103');
insert into #t1 values(4, 'ObjectId', 'B');
insert into #t1 values(4, 'Operation', 'Op4');
insert into #t1 values(4, 'Code', '104');
insert into #t1 values(5, 'ObjectId', 'B');
insert into #t1 values(5, 'Operation', 'Op5');
insert into #t1 values(5, 'Code', '105');
-- create t2
select
rownr,
Max(case when col = 'ObjectId' then val end) as ObjectId,
Max(case when col = 'Operation' then val end) as Operation,
Max(case when col = 'Code' then val end) as Code
into #t2
from #t1
group by rownr
order by rownr, ObjectId;
-- create #t3
-- Maximum number of column groups in result table
select max(cols) into @nr_of_columns from (SELECT count() over (partition by ObjectId) as cols from #t2) A;
-- Create temporary table #t3 to hold results
SET @i = 1;
SET @createTable = 'create table #t3(ObjectId nvarchar(300)';
while @i <= @nr_of_columns loop
set @createTable = @createTable || ', Operation' || @i || ' nvarchar(300), Code' || @i || ' nvarchar(300)';
set @i = @i + 1;
end loop;
set @createTable = @createTable || ')';
execute immediate (@createTable);
-- Pivot into #t3
for whatever as cur cursor for
select 'insert into #t3 select ' || rw as qry from
(select '''' || A.ObjectId || ''' AS ObjectId, ' || LIST(attributes) || repeat(',null,null', @nr_of_columns-A.nr_in_group) AS rw from
(SELECT ObjectId, count() over (partition by ObjectId) nr_in_group, row_number() over (partition by ObjectId order by Operation) nr, ''''||Operation||''' AS Operation' || nr || ',' || '''' || Code || ''' AS Code' || nr as attributes FROM #t2 order by ObjectId,Operation) A
group by ObjectId,@nr_of_columns, nr_in_group) B
DO
execute IMMEDIATE (qry);
end for;
-- Output #t2
select * from #t3;
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.