简体   繁体   English

row_number()通过分区

[英]row_number() over partition by

I have existing PL/SQL code with formatting for the client process that is doing a cursor with case for a join on multiple tables using row_number () over partition by. 我现有的PL / SQL代码具有格式化客户端进程的能力,该进程使用游标来区分在table by by上使用row_number()在多个表上的联接。 It was all fine, till we noticed that if a certain record had multiple contact information on it, the formatting the way it is set, instead of including all the contacts as part of the same record, it is outputting the contacts as different rows for the same customer. 一切都很好,直到我们注意到,如果某个记录上有多个联系人信息,请按照设置方式进行格式化,而不是将所有联系人都包含在同一记录中,而是将联系人输出为不同的行,相同的客户。 How do i tweak the cursor to make it appear as one record with all contact information(s)? 如何调整光标,使其与所有联系信息一起显示为一条记录? Expected : 预期:

+-------+-----------+------------+-------------------+-------------+-----------+-------------------+------------+
|  ID   |    NAME   |   CONTACT1 |       EMAIL1      |    PHONE1   |  CONTACT2 |       EMAIL2      |    PHONE2  |
+-------+-----------+------------+-------------------+-------------+-----------+-------------------+------------+
| 50000 | Customer1 | Rodney     |  Rodney@gmail.com |  1112223333 |  Billy    | Billy@hotmail.com | 4445556666 |
+-------+-----------+------------+-------------------+-------------+-----------+-------------------+------------+

Instead of : 代替 :

+-------+------------+-----------+-------------------+-------------+
|  ID   |    NAME    |  CONTACT1 |       EMAIL1      |   PHONE1    |
+-------+------------+-----------+-------------------+-------------+
| 50000 |  Customer1 | Rodney    | Rodney@gmail.com  |  1112223333 |
| 50000 |  Customer1 | Billy     | Billy@hotmail.com | 4445556666  |
+-------+------------+-----------+-------------------+-------------+

The code is as follows : 代码如下:

cursor c1 is
       select case rn1 when 1 then "TypeOfContract" end "TypeOfContract",
       case rn1 when 1 then "ContractNumber" end "ContractNumber",
       case rn1 when 1 then "ClientName" end "ClientName",
       "AdminName",
       --case rn1 when 1 then "AdminName" end "AdminName",
       --case rn1 when 1 then "TechnicalName" end "TechnicalName",
       "TechnicalName",
       --case rn1 when 1 then "DayToDayName" end "DayToDayName",
       "DayToDayName",
       case rn2 when 1 then "ServiceName" end "ServiceName",
       case rn2 when 1 then "ServiceNumber" end "ServiceNumber",
       "SubserviceName",
       "SubserviceNumber",
       "Map",
       "VolumeOfFilesMessages",
       "VolumeOfPayments",
       "DollarAmountOfPayments"
from (select "TypeOfContract","ContractNumber","ClientName","AdminName","TechnicalName","DayToDayName",
        "ServiceName","ServiceNumber","SubserviceName","SubserviceNumber","Map","VolumeOfFilesMessages","VolumeOfPayments","DollarAmountOfPayments",
        row_number() over (partition by "TypeOfContract","ContractNumber","ClientName","AdminName","TechnicalName","DayToDayName"
        order by "ServiceName","ServiceNumber") rn1,
        row_number() over (partition by "TypeOfContract","ContractNumber","ClientName"/*,"AdminName","TechnicalName","DayToDayName"*/,"ServiceName","ServiceNumber"
        order by null) rn2
          from (
SELECT DISTINCT
case when tctc_cntipcli='C' then 'Host2Host' when tctc_cntipcli='L' then 'File Transfer Services' when tctc_cntipcli='I' then 'Integrated Payables' when tctc_cntipcli='D' then 'Data Exchange'
when tctc_cntipcli='V' then 'Vendor' when tctc_cntipcli='E' then 'External Bank'end as "TypeOfContract" ,
                   tctc_cncclipu as "ContractNumber",
                   regexp_replace(tctc_cndocidc, '[^[:alnum:]'' '']', NULL)  as "ClientName",
                   case when tcct_cncctto = 'A' then (select trim(tcct_cnctname)||trim(tcct_cnemail)||trim(tcct_cnphone) from dual) end as "AdminName"  ,
                  case when tcct_cncctto = 'T' then (select trim(tcct_cnctname)||trim(tcct_cnemail)||trim(tcct_cnphone) from dual) end as "TechnicalName",
                   case when tcct_cncctto = 'D' then (select trim(tcct_cnctname)||trim(tcct_cnemail)||trim(tcct_cnphone) from dual) end as "DayToDayName",
                   tsrv_cndesser as "ServiceName",
                   texe_cnfuncid as "ServiceNumber",
                   tsrs_cnsubsdc as "SubserviceName",
                   texe_cnsubser as "SubserviceNumber",
                   tmap_cndesc   as "Map"
                         from service.kndtctc, service.kndtexe, service.kndtscm, service.kndtsrv, service.kndtsrs, service.kndtmap, service.kndtcct
                          where tctc_cncclipu = texe_cncclipu
                          and texe_cnfuncid = tsrv_cncveser
                          and texe_cnfuncid = tsrs_cncveser
                          and texe_cnsubser = tsrs_cnsubser
                          and texe_cncclipu = tscm_cncontra
                          and tscm_cnmapco = tmap_cnmapco
                          and tscm_cnservic = tsrv_cncveser
                          and tscm_cnsubser = tsrs_cnsubser
                          and texe_cncclipu = tcct_cncclipu
                          and tscm_cncontra = tcct_cncclipu
                          and tctc_cnestado in ('01', '03')
                          and texe_cnestado in ('01', '03')
                          and tsrv_cnestado in ('01', '03')
                          and tsrs_cnestado in ('01', '03')
                          and tscm_cnestado in ('01', '03')
                          and tmap_cnestado in ('01', '03')
                          order by tctc_cncclipu
               ) 
       )
;

Appreciate any help the community can provide! 感谢社区可以提供的任何帮助!

As you are in PL/SQL, it is possible to do this without dynamic SQL. 正如您在PL / SQL中一样,可以在没有动态SQL的情况下执行此操作。 You need to split your cursor into two. 您需要将光标分成两个。 The first will return the main details you need. 第一个将返回您需要的主要详细信息。 That is, this cursor will return one row for every physical row you need to see in the output. 也就是说,此光标将为您需要在输出中看到的每一物理行返回一行。 The second will return one row for every contact. 第二个将为每个联系人返回一行。

You then concatenate the details inside a nested loop. 然后,您将详细信息串联在嵌套循环中。 The rough shape of the code is as follows. 代码的大致形状如下。 It's a bit more code, but will get the effect you seek. 它包含更多代码,但将获得您想要的效果。

DECLARE

    CURSOR c_main
    IS
    SELECT ...

    CURSOR c_contact
    IS
    SELECT ...

    v_full_line  VARCHAR2(4000);

BEGIN

    FOR r_main IN c_main LOOP

        v_full_line := r_main.id || ' | ' || r_main.name || ' | ';

        FOR r_contact IN c_contact(r_main.id) LOOP
            v_full_line := v_full_line || r_contact.contact || ' | ' || r_contact.email || ' | ' || r_contact.phone || ' | ';
        END LOOP;

        -- Return v_full_line here...
    END LOOP;
END;
/

Example with function(p_maxcol - maximum number of columns in your query. You can simply get it just run max(count(*)) on your query). 函数示例(p_maxcol-查询中的最大列数。只需在查询上运行max(count(*))即可获得它)。

CREATE OR REPLACE FUNCTION get_allitems(p_maxcol number)
  RETURN SYS_REFCURSOR
AS
  my_cursor SYS_REFCURSOR;
  res varchar2(32767);
  -- type in this variable your query.
  query varchar2(32767) := q'[(select  50000 as id ,  'Customer1' as NAME, 'Rodney' as CONTACT  , 'Rodney@gmail.com' as EMAIL,  1112223333 as  PHONE   from dual union all
                              select 50000 ,  'Customer1' , 'Billy'    , 'Billy@hotmail.com' , 4445556666  from dual union all
                              select 60000 ,  'Customer2' , 'Garry'    , 'Garry@hotmail.com' , 1232356666  from dual)]';
BEGIN
  res := q'{select id, EXTRACTVALUE(xml,'/PivotSet/item[1]/column[4]') as NAME}';
  for i in 1..p_maxcol loop
    res := res || q'{,EXTRACTVALUE(xml,'/PivotSet/item[}' || i || q'{]/column[1]') as CONTACT }' ||
                  q'{,EXTRACTVALUE(xml,'/PivotSet/item[}' || i || q'{]/column[2]') as EMAIL }' ||
                  q'{,EXTRACTVALUE(xml,'/PivotSet/item[}' || i || q'{]/column[3]') as PHONE }';
  end loop;
  res := res || 'from (select id, contact_email_phone_xml as xml from ' || query || ' pivot xml (max(NAME) as d for (CONTACT,EMAIL,PHONE) in(any,any,any)))';
  OPEN my_cursor FOR res;
  RETURN my_cursor;
END get_allitems;

Usage 用法

select get_allitems(2) from dual

Also take note that the maximum number of column in Oracle is 255. 另请注意,Oracle中的最大列数为255。

In static sql more relative example to you(with concatinating columns) is this(Note. Max column length is 4000): 在静态sql中,与您相对的示例(带有重叠列)是此示例(注意。最大列长为4000):

with t( ID , NAME  ,  CONTACT , EMAIL , PHONE) as(
select  50000 ,  'Customer1' , 'Rodney'   , 'Rodney@gmail.com' ,  1112223333  from dual union all
select 50000 ,  'Customer1' , 'Billy'    , 'Billy@hotmail.com' , 4445556666  from dual union all
select 60000 ,  'Customer2' , 'Garry'    , 'Garry@hotmail.com' , 1232356666  from dual)
select id, name, listagg(CONTACT || '|' || EMAIL || '|' || PHONE || '|') within group (order by CONTACT) from t
 group by  id, name

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

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