[英]Stored procedure to do a two-level pivot
I am trying to create a stored procedure in Sybase
Adaptive Server Anywhere
that will do a double pivot of table. 我正在尝试在
Sybase
Adaptive Server Anywhere
中创建一个存储过程,该存储过程将完成表的双重操作。 I will first outline with some images what I am trying to accomplish. 我将首先用一些图像概述我要完成的工作。
The problem 问题
Here is the raw data in the table; 这是表中的原始数据; in the sample code that I have posted lower down this is temporary table #t1 :
在我下面向下发布的示例代码中,这是临时表#t1:
The first level of pivoting involves grouping on the column rownr
and pivoting on the column col
, putting the resulting table into temporary table #t2 : 数据
rownr
的第一级包括对rownr
列进行分组和对列col
rownr
,将结果表放入临时表#t2中:
I have the code up to this point which I have posted lower down. 到目前为止,我已经发布了下面的代码。
This is the section that I am struggling with. 这是我正在努力的部分。 I am now needing to pivot table #t2 grouping on the column
ObjectId
and replicating the columns Operation
and Code
for the number of rows in the grouping to produce table #t3. 现在,我需要对
ObjectId
列上的表#t2分组进行透视,并为该分组中的行数复制列Operation
和Code
,以生成表#t3。 So the result for the example I have given would look like this: 因此,我给出的示例的结果将如下所示:
Because two columns are being replicated ( Operation
and Code
) the number of columns in the resulting table should equal 2 multiplied by the number of rows in the grouping with the largest number of rows. 因为要复制两列(“
Operation
和Code
),所以结果表中的列数应等于2乘以分组中具有最大行数的行数。 Groupings that have less than the maximum number of grouped rows will be padded with null values, as seen in the example. 如示例所示, 小于分组行的最大数目的分组将被填充为空值。
The code 编码
Here is my code that creates the first two tables, #t1 and #t2 : 这是我的代码,用于创建前两个表#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
Take note 记笔记
Please note that I am trying to solve this for Sybase
Adaptive Server Anywhere
which does not have a pivot
statement like Sql Server
does, so a solution using a pivot
statement will not help me. 请注意,我试图解决这一对
Sybase
Adaptive Server Anywhere
不具有一个pivot
声明像Sql Server
呢,所以使用的解决方案pivot
声明绝不会帮我。
You need each set of A, B, etc in a single temporary table with their ObjectIds, with an ordering integer 1,2,3,4 against the ObjectIDs, regardless of the string value of the op. 您需要在单个临时表中的每组A,B等及其ObjectId,对ObjectID的排序整数为1,2,3,4,而与op的字符串值无关。
Getting such an ordered integer is normally easy with an IDENTITY, but you don't want it for all, you want it per A,B,C etc subset. 有了IDENTITY,获得这样一个有序整数通常很容易,但是您并不想全部都想要它,而是希望每个A,B,C等子集都需要它。
Thus if you can run a Cursor on each ObjectId value (A,B,C,etc.,) and get the integer ordered operations for those into a temp table, then you can pivot easily with multiple outer joins. 因此,如果您可以对每个ObjectId值(A,B,C等)运行Cursor并将这些对象的整数排序操作放入临时表中,则可以轻松进行多个外部联接的数据透视。
So: create table #l(Id NUMERIC(8) IDENTITY, op VARCHAR(30), obj VARCHAR(300)) go 所以:创建表#l(Id NUMERIC(8)IDENTITY,op VARCHAR(30),obj VARCHAR(300))去
set identity_insert #l on
Get a cursor on the objectIds and loop like: 在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'
You will then find that #l can be pivotted nicely with multipler outers, because you'll have a table like: 然后,您会发现#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
Just in case this helps someone else, here is the code that I eventually came up with to accomplish the required double pivot: 以防万一这对其他人有帮助,下面是我最终想出的代码,以完成所需的双重工作:
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.