繁体   English   中英

Oracle SQL 将行转换为列

[英]Oracle SQL to convert rows to columns

我找不到合适的答案,所以我在这里写。 我有一个包含以下字段的表格。

ID           Amount    DocNum   DocStatus   DueDate
AA           2400      00005     1          10-Jun-2019
AA           1400      00006     4          21-Sep-2019
AA           9000      00028     1          22-Aug-2020 
AA           5000      00201     2          31-Aug-2020
AA           6400      00410     1          22-Jan-2021
AA           2000      00511     1          01-Mar-2021
BB           1500      01390     1          01-Jan-2021

我想显示状态为 1 的前 3 个最新文档

ID Document1 Amount1 Document2 Amount2 Document3 Amount3 
AA 00511     2000    00410     6400    00028     9000 
BB 01390     1500    XX        XX      XX        XX

我以为我可以使用 Pivot 或解码但无法确定其他条件。 任何帮助表示赞赏。

您可以使用row_number()和条件聚合:

select id,
       max(case when seqnum = 1 then docnum end) as docnum_1,
       max(case when seqnum = 1 then amount end) as amount_1,
       max(case when seqnum = 2 then docnum end) as docnum_2,
       max(case when seqnum = 2 then amount end) as amount_2,
       max(case when seqnum = 3 then docnum end) as docnum_3,
       max(case when seqnum = 3 then amount end) as amount_3
from (select t.*,
             row_number() over (partition by id order by due_date desc) as seqnum
      from t
      where status = 1
     ) t
group by id;
alter session set nls_date_format='dd-Mon-yyyy';

with
  my_table (id, amount, docnum, docstatus, duedate) as (
    select 'AA', 2400, '00005', 1, to_date('10-Jun-2019') from dual union all
    select 'AA', 1400, '00006', 4, to_date('21-Sep-2019') from dual union all
    select 'AA', 9000, '00028', 1, to_date('22-Aug-2020') from dual union all
    select 'AA', 5000, '00201', 2, to_date('31-Aug-2020') from dual union all
    select 'AA', 6400, '00410', 1, to_date('22-Jan-2021') from dual union all
    select 'AA', 2000, '00511', 1, to_date('01-Mar-2021') from dual union all
    select 'BB', 1500, '01390', 1, to_date('01-Jan-2021') from dual
  )
select id, "1_DOC" as document1, "1_AMT" as amount1,
           "2_DOC" as document2, "2_AMT" as amount2,
           "3_DOC" as document3, "3_AMT" as amount3
from   (
         select id, amount, docnum, 
                row_number() over (partition by id 
                                   order by duedate desc) as rn
         from   my_table
         where  docstatus = 1
       )
pivot  (min(docnum) as doc, min(amount) as amt for rn in (1, 2, 3))
;


ID DOCUMENT1    AMOUNT1 DOCUMENT2    AMOUNT2 DOCUMENT3    AMOUNT3
-- --------- ---------- --------- ---------- --------- ----------
AA 00511           2000 00410           6400 00028           9000
BB 01390           1500     

您需要在子查询中完成所有准备工作:过滤docstatus = 1 ,按到期日期降序创建RN排名, duedate只是 pivot 所需的列。 除了微不足道的旋转(在子查询中完成所有准备工作之后微不足道)之外,外部查询只需要在select子句中稍加注意,以获取正确的列名。

You can dynamically generate the desired SQL SELECT Statement in order to pivot the rows to display whether top 2,3,4..etc by creating such a function with IN parameter to represent the top 2,3,4..etc and returning SYS_REFCURSOR键入结果集为

CREATE OR REPLACE FUNCTION Fn_Pivot_Doc_and_Amounts( numcol INT ) RETURN SYS_REFCURSOR IS
  v_recordset SYS_REFCURSOR;
  v_sql       VARCHAR2(32767);
  v_cols      VARCHAR2(32767);
BEGIN
  SELECT LISTAGG( ''||level||' AS "'||level||'"' , ',' )
                 WITHIN GROUP ( ORDER BY level )
    INTO v_cols
    FROM dual
   CONNECT BY level <= numcol;

  v_sql :='SELECT *
             FROM(SELECT id,docnum,amount,
                         ROW_NUMBER() OVER (PARTITION BY id ORDER BY duedate DESC) AS rn
                    FROM tab t
                   WHERE docstatus = 1)
            PIVOT(
                  MAX(docnum) AS document,
                  MAX(amount) AS amount  FOR rn IN ( '|| v_cols ||'  )
                 )';

  OPEN v_recordset FOR v_sql;
  RETURN v_recordset;
END;

然后从SQL Developer的控制台调用

SQL> DECLARE
       result SYS_REFCURSOR;
BEGIN
   :result := Fn_Pivot_Doc_and_Amounts(2); -- 3,4,...
END;
/

SQL> PRINT result;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM