簡體   English   中英

存儲過程要做兩級樞紐

[英]Stored procedure to do a two-level pivot

我正在嘗試在Sybase Adaptive Server Anywhere中創建一個存儲過程,該存儲過程將完成表的雙重操作。 我將首先用一些圖像概述我要完成的工作。

問題

  1. 原始數據

這是表中的原始數據; 在我下面向下發布的示例代碼中,這是臨時表#t1:

在此處輸入圖片說明

  1. 第一層次的透視

數據rownr的第一級包括對rownr列進行分組和對列col rownr ,將結果表放入臨時表#t2中:

在此處輸入圖片說明

到目前為止,我已經發布了下面的代碼。

  1. 二級樞紐

這是我正在努力的部分。 現在,我需要對ObjectId列上的表#t2分組進行透視,並為該分組中的行數復制列OperationCode ,以生成表#t3。 因此,我給出的示例的結果將如下所示:

在此處輸入圖片說明

因為要復制兩列(“ OperationCode ),所以結果表中的列數應等於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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM