简体   繁体   中英

Issue with the performance of the query

I have two tables tab1 and tab2 each are having two columns acc_num and prod_code. I need to update prod_code in tab2 from tab1. Below is the sample data in both the tables:

TAB1

acnum      Prod
-------------------
1            A
2            B
2            C
3            X
3            X

Tab2

acnum        Prod
-------------------
1            null
2            null
2            null
3            null
3            null

And for the 2nd table after update all the distinct codes should be concatenated. Below is the sample output.

Tab2

acnum       Prod
-------------------
1            A
2            B|C
2            B|C
3            X
3            X

I am able to achieve this through PL/SQL, but it's taking ages to complete. (Actual tables are having millions of records). Below is the code I am using.

DECLARE
  l_acnum dbms_sql.varchar2a;
  l_prod dbms_sql.varchar2a;
  l_prod2 VARCHAR2(10):= NULL;
  l_count NUMBER      := 0;
  CURSOR cr_acnum
  IS
    SELECT DISTINCT(acnum) FROM tab1;
  CURSOR cr_prod(l_acnum_dum IN VARCHAR2)
  IS
    SELECT prod FROM tab1 WHERE acnum = l_acnum_dum;
BEGIN
  OPEN cr_acnum;
  FETCH cr_acnum bulk collect INTO l_acnum;
  CLOSE cr_acnum;
  FOR i IN l_acnum.first .. l_acnum.last
  LOOP
    OPEN cr_prod(l_acnum(i));
    FETCH cr_prod bulk collect INTO l_prod;
    CLOSE cr_prod;
    FOR m IN l_prod.first .. l_prod.last
    LOOP
      IF m          <> 1 THEN
        IF l_prod(m) = l_prod(m-1) THEN
          l_prod2   := l_prod(m);
        ELSE
          l_prod2 := l_prod2||'|'||l_prod(m);
        END IF;
      ELSE
        l_prod2 := l_prod(m);
      END IF;
    END LOOP;
    UPDATE tab2 SET prod = l_prod2 WHERE acnum = l_acnum(i);
  END LOOP;
END;

This pl/sql block is taking ages to complete. Is there anyway I can achieve the same through query rather than PL/SQL or may be by efficient PL/SQL. I tried BULK COLLECT also but of no use. Data is in Oracle DB. Thanks a lot for your time.

This will concatenate those values as long as they don't exceed a certain total length. You may also want to do a subquery to dedupe them if there are any dupes.

Update: here is with LISTAGG

update table2 set Prod = (
SELECT LISTAGG(t1.Prod, ', ') WITHIN GROUP (ORDER BY t1.Prod) "Prod"
  FROM Table1 t1
where t1.acnum = table2.acnum)

Thanks everyone for your input. I achived the same using your inputs. I used 2 step solution:

Step 1) Create a lookup table for product and account no.

create table lkup_tbl
as SELECT  acnum, LISTAGG(Prod, '|') WITHIN GROUP (ORDER BY Prod) product
FROM (select distinct acnum, Prod from  tab1) tab
GROUP BY acnum;

Step 2) Now update all the tables by joining this lookup table.

update  tab2 t1
set (t1.Prod)  = (select product from  lkup_tbl t2
where t2.acnum = t1.acnum
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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