0

EDIT 1: I was able to compile the procedure suggested by @radagast81 but it just keeps running. Any help on this will be appreciated.

I had received solution to split comma separated string in my previous thread. So , I am using below query to split the given string into destination table.

PUSH_DATA_TEMP Cols: DISP_PK-> Primary key should be uniqe incrementing numbers per id. PID-> ID for every string col1........col11

insert into push_data_temp (pid,col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12)
with rcte (id, data, lvl, result) as (
  select id, data, 1,
    regexp_substr(data, '("[^"]*"|[^, "]+)', 1, 1, null, 1) )
  from disp_data
  union all
  select id, data, lvl + 1,
   regexp_substr(data, '("[^"]*"|[^, "]+)', 1, lvl + 1, null, 1) 
  from rcte
  where lvl <= regexp_count(data, '("[^"]*"|[^, "]+)')
)
select *
from (
  select disp_pk,id, lvl, replace(result,'""','') as final
  from rcte
)
pivot (max(result) as col for (lvl) in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12));

However i have additional requirement now to use pl/sql procedure and split & insert/update rows if already existing, all dynamically.

  1. I need to make the columns above dynamic, so the string could get split in 11 columns as above or 15. Maximum number is 30.

So i need to write a procedure, that splits and pushes string into columns dynamically.

  1. So it should insert rows and if the row already exists, update the columns, both dynamically. Probably with loops. So condition for inset and update for each row is mandatory. ID/PID is the id of the row.

DB-12C

  1. For id_pk, it should be unique number generated incrementing by 1. ID/PID, needs to be passed majorly as parameter which identifies each string.

Sample data: The first string for PID=100 has string split into 11 columns and the second with PID=110 will split into 12 columns and so on.

create table disp_data(id number, data varchar2(4000));

Insert into disp_data(id,data) values(100,
'"Project title as per the outstanding Requirements","The values are, not with respect to the requirement and analysis done by the team. 
Also it is difficult to, prepare a scenario notwithstanding the fact it is difficult. This user story is going to be slightly complex however it is up to the team","Active","Disabled","25 tonnes of fuel","www.examplesites.com/html.asp&net;","","","","","25"');

Insert into disp_data(id,data) values(110,
'"Project title afor BYU heads","The values are, exactly up to the requirement and analysis done by the team. 
Also it is difficult to, prepare a scenario notwithstanding the fact it is difficult. This user story is going to be slightly complex however it is up to the team","Active","Disabled","25 tonnes of fuel","www.examplesites.com/html.asp&net;","Apprehension","","","","25","Stable"');
Velocity
  • 433
  • 5
  • 32
  • Have you tried `execute immediate '';`? It could be something like `for i in (select id, data from disp_data /*other conditions*/) loop v_sql := 'insert into push_data_temp values ('||i.id||','||replace(replace(i.data,'''', ''''''), '"', '''')||')'; execute immediate v_sql; end loop;`. Doc: https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/EXECUTE-IMMEDIATE-statement.html#GUID-C3245A95-B85B-4280-A01F-12307B108DC8 – KayaNatsumi Aug 13 '20 at 13:02
  • Just use second answer by Chris Saxon about polymorhic functions in your previous question: https://stackoverflow.com/a/63359027/429100 – Sayan Malakshinov Aug 13 '20 at 17:46
  • Unfortunately, previously i had 19c, but now have been asked to give this solution on 12 c. PTF are supported 18c onwards so i cannot use them – Velocity Aug 14 '20 at 03:46

1 Answers1

2

You can basically use your existing SELECT and then simply put it into a MERGE-Statement:

WITH dat(id, DATA) AS (SELECT 110,'"Project title afor BYU heads","The values are, exactly up to the requirement and analysis done by the team. 
Also it is difficult to, prepare a scenario notwithstanding the fact it is difficult. This user story is going to be slightly complex however it is up to the team","Active","Disabled","25 tonnes of fuel","www.examplesites.com/html.asp&net;","Apprehension","","","","25","Stable"' FROM dual)
MERGE INTO push_data_temp tgt
USING (SELECT * 
         FROM (SELECT id
                    , LEVEL lvl
                    , REPLACE(regexp_substr(data, '("[^"]*"|[^, "]+)', 1, level, null, 1),'""','') result
                 FROM dat
              CONNECT BY regexp_substr(data, '("[^"]*"|[^, "]+)', 1, level, null, 1) IS NOT NULL)
       pivot (max(result) as col for (lvl) in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30)) src
  ON (src.id = tgt.pid)
WHEN MATCHED THEN UPDATE
 SET col1 = src."1_COL"
   , ...
   , col30 = src."30_COL"
WHEN NOT MATCHED THEN INSERT (pid, col1, ..., col30)
VALUES (src.id, src."1_COL", ..., src."30_COL")

Wrapping this logic into a Procedure is also fairly easy:

CREATE OR REPLACE 
PROCEDURE PUSH_DATA(id INTEGER, DAT VARCHAR2) IS
BEGIN
  MERGE INTO push_data_temp tgt
  USING (SELECT * 
           FROM (SELECT id
                      , LEVEL lvl
                      , REPLACE(regexp_substr(dat, '("[^"]*"|[^, "]+)', 1, level, null, 1),'""','') result
                   FROM dual
                CONNECT BY regexp_substr(dat, '("[^"]*"|[^, "]+)', 1, level, null, 1) IS NOT NULL)
         pivot (max(result) as col for (lvl) in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30)) src
    ON (src.id = tgt.pid)
  WHEN MATCHED THEN UPDATE
   SET col1 = src."1_COL"
     , ...
     , col30 = src."30_COL"
  WHEN NOT MATCHED THEN INSERT (pid, col1, ..., col30)
  VALUES (src.id, src."1_COL", ..., src."30_COL");
END;

You can then call it as following:

BEGIN
  PUSH_DATA(110,'"Project title afor BYU heads","The values are, exactly up to the requirement and analysis done by the team. 
Also it is difficult to, prepare a scenario notwithstanding the fact it is difficult. This user story is going to be slightly complex however it is up to the team","Active","Disabled","25 tonnes of fuel","www.examplesites.com/html.asp&net;","Apprehension","","","","25","Stable"');
END;
Radagast81
  • 2,921
  • 1
  • 7
  • 21
  • Sure this would work, but how can this get wrapped in procedure also ? I am not good with procs so if you could help it would be great! – Velocity Aug 14 '20 at 06:05
  • Hi, I triedthe first solution of merge statement with WITH clause but it is throwing error onthe Merge line Not sure but merge and with together are creating issue. Error is missing select keyword. Also in with clause i need to take as with(id,data) as (select id,data from disp_data) because the purpose is to make dynamic. Where am i going wrong? – Velocity Aug 15 '20 at 07:20
  • Please check this : https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=e71524a3d15275891b375f46e11ea012 – Velocity Aug 15 '20 at 07:40
  • i have updated original post with the procedure i tried running and its running indefinitely. Could you take a look? – Velocity Aug 16 '20 at 16:27
  • 1
    @Vini: The reason could be the parameter name you have provided in procedure as `id` creating any issue which I didn't really debug. I have not put any effort as others to answer your question but just helping further. However I have tried and its working. Please see the dbfiddle and give feedback.https://dbfiddle.uk/?rdbms=oracle_18&fiddle=4bb8dd2f249928557f4645ecdf09f554 . good luck!! – Sujitmohanty30 Aug 16 '20 at 17:26
  • FYI.Made some small renaming changes. changed the parameter name and the instead sticking to dynamic column names because of pivot used mine – Sujitmohanty30 Aug 16 '20 at 17:27
  • Hi Sujit, thanks a lot. it worked but somehow when i am running it in real db, the proc as well as query is just running indefinitely. Not sure what's wrong.. – Velocity Aug 16 '20 at 18:33
  • The database is 12 c. – Velocity Aug 16 '20 at 18:36
  • Do you have more data in the source table in actual database ? And also I was thinking why do you need the parameter in the procedure where it's not used inside ? I could wild guess if you have huge data and merge would take time because of pivot and then you should think of using collection to do it ? – Sujitmohanty30 Aug 16 '20 at 19:02
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/219933/discussion-between-vini-and-sujitmohanty30). – Velocity Aug 17 '20 at 04:02
  • 1
    @Vini check I have replied in chat about the clarification with passing the string. – Sujitmohanty30 Aug 18 '20 at 17:06