我有现有的PL / SQL代码,其中包含客户端进程的格式化,该进程使用row_number()over partition by来执行多个表上的连接的情况。一切都很好,直到我们注意到如果某个记录上有多个联系人信息,格式化它的设置方式,而不是将所有联系人包括在同一记录中,它将联系人输出为不同的行同一个客户。如何调整光标使其显示为包含所有联系信息的一条记录? 预期:
+-------+-----------+------------+-------------------+-------------+-----------+-------------------+------------+
| ID | NAME | CONTACT1 | EMAIL1 | PHONE1 | CONTACT2 | EMAIL2 | PHONE2 |
+-------+-----------+------------+-------------------+-------------+-----------+-------------------+------------+
| 50000 | Customer1 | Rodney | Rodney@gmail.com | 1112223333 | Billy | Billy@hotmail.com | 4445556666 |
+-------+-----------+------------+-------------------+-------------+-----------+-------------------+------------+
而不是:
+-------+------------+-----------+-------------------+-------------+
| ID | NAME | CONTACT1 | EMAIL1 | PHONE1 |
+-------+------------+-----------+-------------------+-------------+
| 50000 | Customer1 | Rodney | Rodney@gmail.com | 1112223333 |
| 50000 | Customer1 | Billy | Billy@hotmail.com | 4445556666 |
+-------+------------+-----------+-------------------+-------------+
代码如下:
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
)
)
;
感谢社区提供的任何帮助!
答案 0 :(得分:0)
当您使用PL / SQL时,可以在没有动态SQL的情况下执行此操作。您需要将光标分成两部分。第一个将返回您需要的主要细节。也就是说,此光标将为您需要在输出中看到的每个物理行返回一行。第二个将为每个联系返回一行。
然后,您可以在嵌套循环中连接细节。代码的粗略形状如下。这需要更多的代码,但会得到你想要的效果。
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;
/
答案 1 :(得分:0)
函数示例(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;
用法
select get_allitems(2) from dual
另请注意,Oracle中的最大列数为255。
在静态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