I have a procedure which is used for extracting data and then inserting them. My problem is that I am using BULK COLLECTION. My goal is that I want to every time extract for example 10,000 data then insert these 10,000 records. But in my script I can limit it with that value but it doesn't insert more. For instance I have 6 records and I used 4 with LIMIT clause. What I want is the procedure should first insert 4 record then extract remaining 2 records for example.
I have I can describe issue briefly. I am open to any fix advices in my scripts. Thank you from now.
I solved my problem added new version of script below, thank you everyone
create or replace procedure GPU_DATA_EXTRACTOR_TEST(pid_billdate DATE) is
v_cnt NUMBER;
c_limit CONSTANT PLS_INTEGER DEFAULT 4;
CURSOR c1 IS
SELECT DISTINCT intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab
WHERE abr.CHRG_TP = 'INSTALLMENT'
AND abr.TAX_CATG_ID = 'NOTAX'
AND abr.acct_bill_id = ab.acct_bill_id
AND ab.bill_date = pid_billdate;
TYPE prod_ids_t IS TABLE OF apld_bill_rt.intl_prod_id%TYPE INDEX BY PLS_INTEGER;
l_prod_ids prod_ids_t;
begin
execute immediate 'truncate table GPU_INV_TEST';
v_cnt := 0;
OPEN c1;
LOOP
FETCH c1 BULK COLLECT INTO l_prod_ids LIMIT c_limit;
EXIT WHEN l_prod_ids.COUNT = 0;
FOR indx IN 1 .. l_prod_ids.COUNT
loop
INSERT INTO GPU_INV_TEST
SELECT AB.ACCT_BILL_ID,
AB.BILL_NO,
AB.INV_ID,
AB.BILL_DATE,
ba2.bill_acct_id,
ba1.bill_acct_id parent_bill_acct_id,
AB.DUE_DATE,
PG.CMPG_ID,
ABR.NET_AMT,
AB.DUE_AMT,
P.PROD_NUM,
pds.DST_ID,
ABR.DESCR,
p.intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab,
prod p,
FCBSADM.PROD_DST pds,
bill_acct_prod bap,
bill_acct ba1,
bill_acct ba2,
prod_cmpg pg
WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
AND ba2.intl_bill_acct_id = bap.intl_bill_acct_id
AND bap.intl_prod_id = abr.intl_prod_id
AND ABR.CHRG_TP = 'INSTALLMENT'
AND bap.intl_prod_id = pds.intl_prod_id
AND bap.intl_prod_id = p.intl_prod_id
AND p.intl_prod_id = pg.intl_prod_id(+)
AND ABR.intl_prod_id = l_prod_ids(indx)
UNION
SELECT AB.ACCT_BILL_ID,
AB.BILL_NO,
AB.INV_ID,
AB.BILL_DATE,
ba1.bill_acct_id,
ba1.bill_acct_id parent_bill_acct_id,
AB.DUE_DATE,
PG.CMPG_ID,
ABR.NET_AMT,
AB.DUE_AMT,
P.PROD_NUM,
pds.DST_ID,
ABR.DESCR,
p.intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab,
prod p,
FCBSADM.PROD_DST pds,
bill_acct_prod bap,
bill_acct ba1,
prod_cmpg pg
WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
--AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
AND ba1.intl_bill_acct_id = bap.intl_bill_acct_id
AND bap.intl_prod_id = abr.intl_prod_id
AND ABR.CHRG_TP = 'INSTALLMENT'
AND bap.intl_prod_id = pds.intl_prod_id
AND bap.intl_prod_id = p.intl_prod_id
AND p.intl_prod_id = pg.intl_prod_id(+)
AND ABR.intl_prod_id = l_prod_ids(indx);
v_cnt := v_cnt + 1;
IF MOD (v_cnt, 4) = 0
THEN
COMMIT;
END IF;
end loop;
COMMIT;
END LOOP;
CLOSE c1;
end;
You need a LOOP in order to fetch multiple subsets of records. Example snippet:
...
loop
FETCH c1 BULK COLLECT INTO l_prod_ids LIMIT c_limit;
exit when l_prod_ids.count = 0;
FOR indx IN 1 .. l_prod_ids.COUNT
...
end loop;
CLOSE c1;
...
Incidentally, executing thousands of individual INSERT statements is a recipe for poor performance. You should use the FORALL syntax (which is not a loop) to execute a set-based insert operation driving from your collection. Find out more.
You should also give consideration as to whether you ought to be using a collection at all, when you could just use a pure SQL INSERT INTO ... SELECT ... FROM statement. That would perform even better than a FORALL operation.
Related
I have a procedure which is used for extracting data and inserting them into one table. My problem is that I want to get previous months data by looking at bill_account_billcycle table's bill_date column. I have already seen so many examples about first and last day of previous month but I am looking for exactly the last month. Because bill date changes for ever customer in my case?
AND ab.bill_date = bab.bill_date;
so if I can look at previous month of bab.bill_date, I think it cant treat everyting. I am adding my procedure's scripts and one row from bill_account_cycle.bill_date for an example
I am open to any advices thank you from now.
create or replace procedure GPU_DATA_EXTRACTOR_TEST is
c_limit CONSTANT PLS_INTEGER DEFAULT 10000;
CURSOR c1 IS
SELECT DISTINCT intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab,
bill_acct_billcycle bab
WHERE abr.CHRG_TP = 'INSTALLMENT'
AND abr.TAX_CATG_ID = 'NOTAX'
AND abr.acct_bill_id = ab.acct_bill_id
AND ab.bill_date = bab.bill_date;
TYPE prod_ids_t IS TABLE OF apld_bill_rt.intl_prod_id%TYPE INDEX BY PLS_INTEGER;
l_prod_ids prod_ids_t;
begin
execute immediate 'truncate table GPU_INV_TEST';
OPEN c1;
LOOP
FETCH c1 BULK COLLECT INTO l_prod_ids LIMIT c_limit;
EXIT WHEN l_prod_ids.COUNT = 0;
FORALL indx IN 1 .. l_prod_ids.COUNT
INSERT INTO GPU_INV_TEST
SELECT AB.ACCT_BILL_ID,
AB.BILL_NO,
AB.INV_ID,
AB.BILL_DATE,
ba2.bill_acct_id,
ba1.bill_acct_id parent_bill_acct_id,
AB.DUE_DATE,
PG.CMPG_ID,
ABR.NET_AMT,
AB.DUE_AMT,
P.PROD_NUM,
pds.DST_ID,
ABR.DESCR,
p.intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab,
prod p,
FCBSADM.PROD_DST pds,
bill_acct_prod bap,
bill_acct ba1,
bill_acct ba2,
prod_cmpg pg
WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
AND ba2.intl_bill_acct_id = bap.intl_bill_acct_id
AND bap.intl_prod_id = abr.intl_prod_id
AND ABR.CHRG_TP = 'INSTALLMENT'
AND bap.intl_prod_id = pds.intl_prod_id
AND bap.intl_prod_id = p.intl_prod_id
AND p.intl_prod_id = pg.intl_prod_id(+)
AND ABR.intl_prod_id = l_prod_ids(indx)
UNION
SELECT AB.ACCT_BILL_ID,
AB.BILL_NO,
AB.INV_ID,
AB.BILL_DATE,
ba1.bill_acct_id,
ba1.bill_acct_id parent_bill_acct_id,
AB.DUE_DATE,
PG.CMPG_ID,
ABR.NET_AMT,
AB.DUE_AMT,
P.PROD_NUM,
pds.DST_ID,
ABR.DESCR,
p.intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab,
prod p,
FCBSADM.PROD_DST pds,
bill_acct_prod bap,
bill_acct ba1,
prod_cmpg pg
WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
--AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
AND ba1.intl_bill_acct_id = bap.intl_bill_acct_id
AND bap.intl_prod_id = abr.intl_prod_id
AND ABR.CHRG_TP = 'INSTALLMENT'
AND bap.intl_prod_id = pds.intl_prod_id
AND bap.intl_prod_id = p.intl_prod_id
AND p.intl_prod_id = pg.intl_prod_id(+)
AND ABR.intl_prod_id = l_prod_ids(indx);
COMMIT;
END LOOP;
CLOSE c1;
end;
I am looking for exactly the last month
If "last month" is "previous month", then you'd use values returned by
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> select trunc(add_months(sysdate, -1), 'mm') date_from,
2 trunc(sysdate, 'mm') - 1 as date_to
3 from dual
4 /
DATE_FROM DATE_TO
---------- ----------
01.09.2021 30.09.2021
SQL>
and your query might look like
AND ab.bill_date BETWEEN trunc(add_months(sysdate, -1), 'mm')
AND trunc(sysdate, 'mm') - 1
AND ab.bill_date = bab.bill_date
I have a procedure and it is used for inserting a table. It takes another table's datas and join them together then inserting new table.
In this procedure I want to use bulk collections for making these operations more faster. I am challenging in syntax and where to use these bulk collections.
Does anybody help or share ideas with me?
I am adding my database scripts below, thank you from now.
CREATE OR REPLACE procedure FCBSADM.extract_monthly_data(pid_billdate DATE) is
v_cnt NUMBER;
begin
execute immediate 'truncate table gpu';
v_cnt := 0;
FOR REC in (SELECT DISTINCT intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab
WHERE abr.cdate > SYSDATE - 5
AND abr.CHRG_TP = 'INSTALLMENT'
AND abr.TAX_CATG_ID = 'NOTAX'
AND abr.acct_bill_id = ab.acct_bill_id
AND ab.bill_date = pid_billdate)
loop
INSERT INTO GPU
SELECT AB.ACCT_BILL_ID,
AB.BILL_NO,
AB.INV_ID,
AB.BILL_DATE,
ba2.bill_acct_id,
ba1.bill_acct_id parent_bill_acct_id,
AB.DUE_DATE,
PG.CMPG_ID,
ABR.NET_AMT,
AB.DUE_AMT,
P.PROD_NUM,
pds.DST_ID,
ABR.DESCR,
p.intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab,
prod p,
FCBSADM.PROD_DST pds,
bill_acct_prod bap,
bill_acct ba1,
bill_acct ba2,
prod_cmpg pg
WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
AND ba2.intl_bill_acct_id = bap.intl_bill_acct_id
AND bap.intl_prod_id = abr.intl_prod_id
AND ABR.CHRG_TP = 'INSTALLMENT'
AND abr.cdate > SYSDATE - 5
AND ABR.intl_prod_id = rec.intl_prod_id
AND bap.intl_prod_id = pds.intl_prod_id
AND bap.intl_prod_id = p.intl_prod_id
AND p.intl_prod_id = pg.intl_prod_id(+);
v_cnt := v_cnt + 1;
IF MOD (v_cnt, 1000) = 0
THEN
COMMIT;
END IF;
COMMIT;
end loop;
COMMIT;
end;
/
This is the last version of it. Errors are gone but no record is coming to GPU table and I am working on it.
create or replace procedure extract_monthly_data(pid_billdate DATE) is
v_cnt NUMBER;
TYPE prod_ids_t IS TABLE OF apld_bill_rt.intl_prod_id%TYPE INDEX BY PLS_INTEGER;
l_prod_ids prod_ids_t;
begin
execute immediate 'truncate table gpu';
v_cnt := 0;
SELECT DISTINCT abr.intl_prod_id, ab.bill_date BULK COLLECT INTO l_prod_ids
FROM apld_bill_rt abr,
acct_bill ab
WHERE abr.cdate > SYSDATE - 1000
AND abr.CHRG_TP = 'INSTALLMENT'
AND abr.TAX_CATG_ID = 'NOTAX'
AND abr.acct_bill_id = ab.acct_bill_id
ORDER BY bill_date;
FOR indx IN 1 .. l_prod_ids.COUNT
loop
INSERT INTO GPU
SELECT AB.ACCT_BILL_ID,
AB.BILL_NO,
AB.INV_ID,
AB.BILL_DATE,
ba2.bill_acct_id,
ba1.bill_acct_id parent_bill_acct_id,
AB.DUE_DATE,
PG.CMPG_ID,
ABR.NET_AMT,
AB.DUE_AMT,
P.PROD_NUM,
pds.DST_ID,
ABR.DESCR,
p.intl_prod_id
FROM apld_bill_rt abr
JOIN acct_bill ab ON AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
JOIN FCBSADM.PROD_DST pds ON
JOIN bill_acct_prod bap ON bap.intl_prod_id = abr.intl_prod_id
AND bap.intl_prod_id = pds.intl_prod_id
AND bap.intl_prod_id = p.intl_prod_id
JOIN prod p ON bap.intl_prod_id = p.intl_prod_id
JOIN bill_acct ba1 ON ab.intl_bill_acct_id = ba1.intl_bill_acct_id
JOIN bill_acct ba2 ON ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
AND ba2.intl_bill_acct_id = bap.intl_bill_acct_id
LEFT OUTER JOIN prod_cmpg pg ON p.intl_prod_id = pg.intl_prod_id
WHERE ABR.CHRG_TP = 'INSTALLMENT'
AND abr.cdate > SYSDATE - 5
AND ABR.intl_prod_id =ANY (
SELECT intl_prod_id
FROM apld_bill_rt abr
JOIN acct_bill ab ON abr.acct_bill_id = ab.acct_bill_id
WHERE abr.cdate > SYSDATE - 1000
AND abr.CHRG_TP = 'INSTALLMENT'
AND abr.TAX_CATG_ID = 'NOTAX'
);
v_cnt := v_cnt + 1;
IF MOD (v_cnt, 1000) = 0
THEN
COMMIT;
END IF;
end loop;
COMMIT;
end;
This is the table that I want to insert into. The procedure compiled successfully but doesnt insert any record.
create table GPU
(
acct_bill_id NUMBER(16),
bill_no VARCHAR2(30 CHAR),
inv_id VARCHAR2(20 CHAR),
bill_date DATE,
bill_acct_id NUMBER(38),
parent_bill_acct_id NUMBER(38),
due_date DATE,
cmpg_id NUMBER,
net_amt NUMBER(16,2),
due_amt NUMBER(16,2),
prod_num VARCHAR2(32 CHAR),
dst_id NUMBER(22) not null,
descr VARCHAR2(100 CHAR),
intl_prod_id NUMBER(14) not null
);
You would not need any loop or bulk collect, but it is up to you. The reason is that you have all the values in the select distinct , and you are joining this dataset against the main query. It would be much better use a simple insert inside the procedure.
By the way, you should try to avoid this old syntax and start using normal SQL ANSI which is much easier to understand and maintain.
Option 1
Without cursor, nor bulk collect, just a simple insert select
CREATE OR REPLACE procedure FCBSADM.extract_monthly_data( pid_billdate DATE) is
begin
execute immediate 'truncate table gpu';
-- direct path is faster here, as you are truncating the table before
INSERT /*+append */ INTO GPU
with x as ( SELECT DISTINCT intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab
WHERE abr.cdate > SYSDATE - 5
AND abr.CHRG_TP = 'INSTALLMENT'
AND abr.TAX_CATG_ID = 'NOTAX'
AND abr.acct_bill_id = ab.acct_bill_id
AND ab.bill_date = pid_billdate
)
SELECT AB.ACCT_BILL_ID,
AB.BILL_NO,
AB.INV_ID,
AB.BILL_DATE,
ba2.bill_acct_id,
ba1.bill_acct_id parent_bill_acct_id,
AB.DUE_DATE,
PG.CMPG_ID,
ABR.NET_AMT,
AB.DUE_AMT,
P.PROD_NUM,
pds.DST_ID,
ABR.DESCR,
p.intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab,
prod p,
FCBSADM.PROD_DST pds,
bill_acct_prod bap,
bill_acct ba1,
bill_acct ba2,
prod_cmpg pg,
x
WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
AND ba2.intl_bill_acct_id = bap.intl_bill_acct_id
AND bap.intl_prod_id = abr.intl_prod_id
AND ABR.CHRG_TP = 'INSTALLMENT'
AND abr.cdate > SYSDATE - 5
AND ABR.intl_prod_id = x.intl_prod_id
AND bap.intl_prod_id = pds.intl_prod_id
AND bap.intl_prod_id = p.intl_prod_id
AND p.intl_prod_id = pg.intl_prod_id(+);
COMMIT;
end;
Option 2
If you want to use bulk collect, which I don't recommend it here, one option might be. Check for any syntax error, as I did not have any way to replicate the code
CREATE OR REPLACE procedure FCBSADM.extract_monthly_data(pid_billdate DATE) is
v_cnt NUMBER;
TYPE prod_ids_t IS TABLE OF apld_bill_rt.intl_prod_id%TYPE INDEX BY PLS_INTEGER; -- whatever the table is
l_prod_ids prod_ids_t;
begin
execute immediate 'truncate table gpu';
v_cnt := 0;
SELECT DISTINCT intl_prod_id BULK COLLECT INTO l_prod_ids
FROM apld_bill_rt abr,
acct_bill ab
WHERE abr.cdate > SYSDATE - 5
AND abr.CHRG_TP = 'INSTALLMENT'
AND abr.TAX_CATG_ID = 'NOTAX'
AND abr.acct_bill_id = ab.acct_bill_id
AND ab.bill_date = pid_billdate);
FOR indx IN 1 .. l_prod_ids.COUNT
loop
INSERT INTO GPU
SELECT AB.ACCT_BILL_ID,
AB.BILL_NO,
AB.INV_ID,
AB.BILL_DATE,
ba2.bill_acct_id,
ba1.bill_acct_id parent_bill_acct_id,
AB.DUE_DATE,
PG.CMPG_ID,
ABR.NET_AMT,
AB.DUE_AMT,
P.PROD_NUM,
pds.DST_ID,
ABR.DESCR,
p.intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab,
prod p,
FCBSADM.PROD_DST pds,
bill_acct_prod bap,
bill_acct ba1,
bill_acct ba2,
prod_cmpg pg
WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
AND ba2.intl_bill_acct_id = bap.intl_bill_acct_id
AND bap.intl_prod_id = abr.intl_prod_id
AND ABR.CHRG_TP = 'INSTALLMENT'
AND abr.cdate > SYSDATE - 5
AND ABR.intl_prod_id = l_prod_ids(indx)
AND bap.intl_prod_id = pds.intl_prod_id
AND bap.intl_prod_id = p.intl_prod_id
AND p.intl_prod_id = pg.intl_prod_id(+);
v_cnt := v_cnt + 1;
IF MOD (v_cnt, 1000) = 0
THEN
COMMIT;
END IF;
end loop;
COMMIT;
end;
After executing below select , How to assign it into variables.
If input string is "x/y/z" , I have to store "x" into variable say A ,"y" into variable B and z into variable "C".
Suppose if string is "x/z" then I have to store "x" into variable say A but z into variable "c".
in all other cases suppose if input string is only "x" or "x/y/z/z" then nothing can be stored
SELECT REGEXP_SUBSTR(<<Input String>>, '[^/]+', 1, LEVEL)
FROM DUAL
CONNECT BY REGEXP_SUBSTR((<<Input String>>, '[^/]+', 1, LEVEL)
IS NOT NULL;
Instead of using SQL, I would just use PL/SQL, since there seems no need to introduce an unnecessary context switch:
declare
v_a varchar2(10);
v_b varchar2(10);
v_c varchar2(10);
v_string varchar2(33);
procedure split_string (p_string in varchar2,
p_a out varchar2,
p_b out varchar2,
p_c out varchar2)
is
begin
if regexp_count(p_string, '/') = 2 then
p_a := regexp_substr(p_string, '[^/]+', 1, 1);
p_b := regexp_substr(p_string, '[^/]+', 1, 2);
p_c := regexp_substr(p_string, '[^/]+', 1, 3);
elsif regexp_count(p_string, '/') = 1 then
p_a := regexp_substr(p_string, '[^/]+', 1, 1);
p_c := regexp_substr(p_string, '[^/]+', 1, 2);
end if;
end;
begin
v_string := 'x/y/z';
split_string(v_string, v_a, v_b, v_c);
dbms_output.put_line('v_string = "'||v_string||'", v_a = "'||v_a||'", v_b = "'||v_b||'", v_c = "'||v_c||'"');
v_string := 'x/y';
split_string(v_string, v_a, v_b, v_c);
dbms_output.put_line('v_string = "'||v_string||'", v_a = "'||v_a||'", v_b = "'||v_b||'", v_c = "'||v_c||'"');
v_string := 'x/y/z/1';
split_string(v_string, v_a, v_b, v_c);
dbms_output.put_line('v_string = "'||v_string||'", v_a = "'||v_a||'", v_b = "'||v_b||'", v_c = "'||v_c||'"');
v_string := 'x';
split_string(v_string, v_a, v_b, v_c);
dbms_output.put_line('v_string = "'||v_string||'", v_a = "'||v_a||'", v_b = "'||v_b||'", v_c = "'||v_c||'"');
end;
/
v_string = "x/y/z", v_a = "x", v_b = "y", v_c = "z"
v_string = "x/y", v_a = "x", v_b = "", v_c = "y"
v_string = "x/y/z/1", v_a = "", v_b = "", v_c = ""
v_string = "x", v_a = "", v_b = "", v_c = ""
If you absolutely must use SQL, there is no need to use the connect by - you can just separate the results into 3 columns to match the 3 variables you want to input the results into:
with strings as (select 'x/y/z' str from dual union all
select 'x/y' str from dual union all
select 'x/y/z/1' str from dual union all
select 'x' str from dual)
select str,
case when regexp_count(str, '/') in (1, 2) then regexp_substr(str, '[^/]+', 1, 1) end v_a,
case when regexp_count(str, '/') = 2 then regexp_substr(str, '[^/]+', 1, 2) end v_b,
case when regexp_count(str, '/') = 2 then regexp_substr(str, '[^/]+', 1, 3)
when regexp_count(str, '/') = 1 then regexp_substr(str, '[^/]+', 1, 2)
end v_c
from strings;
STR V_A V_B V_C
------- --------------------- --------------------- ---------------------
x/y/z x y z
x/y x y
x/y/z/1
x
Be careful, regex_substr using the format '[^/]+' to parse the string elements do not handle null list elements. Here's a way to extract a specific element from a list that handles nulls, which can be put into a function for reuse (this gets the first element where the separator is a slash):
REGEXP_SUBSTR(string_in, '(.*?)(/|$)', 1, 1, NULL, 1);
See the link above, but call like this simple example where the list elements are extracted in order by a function called get_list_element and assigned to variables. Perhaps you can apply this logic to your needs:
SQL> declare
2 a varchar2(1);
3 b varchar2(1);
4 c varchar2(1);
5 begin
6 select get_list_element('x/y/z', 1, '/'),
7 get_list_element('x/y/z', 2, '/'),
8 get_list_element('x/y/z', 3, '/')
9 into a, b, c
10 from dual;
11
12 dbms_output.put_line('a: ' || a);
13 dbms_output.put_line('b: ' || b);
14 dbms_output.put_line('c: ' || c);
15 end;
16 /
a: x
b: y
c: z
PL/SQL procedure successfully completed.
SQL>
Or fix your original try at turning your elements into rows with this:
SQL> with tbl(str) as (
2 select 'x/y/z' from dual
3 )
4 select regexp_substr(str, '(.*?)(/|$)', 1, level, null, 1) element
5 from tbl
6 connect by level <= regexp_count(str, '/')+1;
ELEME
-----
x
y
z
SQL>
I have 3 records in ClientDataSet with structure:
Num: integer; Start: TTime; End: TTime;
1; 9:00; 10:00
2; 9:30; 10:00
3; 9:40; 10:20
I have to get those records to other ClientDataSet like this:
1; 9:00; 9:30
2: 9:30; 9:40
3; 9:40; 10:00
4; 10:00; 10:20
use TList<TTime>, populate it with both columns, sort it, then iterate through the list skipping duplicates. Like this.
var l: TList<TTime>; t1, t2: TTime; id2: cardinal;
begin
l := TList<TTime>.Create;
try
cds1.First;
while not cds1.Eof do begin
l.Add( Frac(cds1.Fields[1].AsDateTime) );
l.Add( Frac(cds1.Fields[2].AsDateTime) );
cds1.Next;
end;
l.Sort;
cds2.Clear;
if l.Count <= 0 then exit;
t1 := l[0]; id2 := 0;
for t2 in l do begin
if t1 > t2 then raise Exception.create ('Sort silently failed!') else
if t1 < t2 then begin
Inc(id2);
cds2.AppendRecord([ id2, t1, t2 ]);
t1 := t2;
end;
end;
finally
l.Free;
end;
end;
I have folowing Dataout put from my query
**Date** **HIGH** **LOW** **IMAGE** **TYPE**
1/28/2012 69 42 1.jpg SUN
1/29/2012 70 42 2.jpg MSUN
I want to Convert this Output into
**1/28/2012** **1/29/2012**
1.jpg 2.jpg
Sun MSUN
69 72
42 42
Here is My query
SELECT
W_DATE,HIGH, LOW,
W_TYPE, IMAGE
FROM WEATHER
ORDER BY W_DATE ASC
And Also I have multiple dates in rows i want to display only 4 dates and they should change when system date is chanaged
About all the possibilities how get from rows to columns in oracle you can read up here:
http://www.dba-oracle.com/t_converting_rows_columns.htm
I don't see a straight forward solution for that from database point of view - would suggest to do the formatting on application side, otherwise it could look as lame as this:
SELECT
to_char(w1.w_Date,'MM/DD/YYYY'), to_char(w2.w_Date,'MM/DD/YYYY'),
to_char(w3.w_Date,'MM/DD/YYYY'), to_char(w4.w_Date,'MM/DD/YYYY')
FROM
(select * from weather where w_date = trunc(sysdate)) w1,
(select * from weather where w_date = trunc(sysdate) + 1) w2,
(select * from weather where w_date = trunc(sysdate) + 2) w3,
(select * from weather where w_date = trunc(sysdate) + 3) w4
UNION ALL
SELECT
w1.image, w2.image, w3.image , w4.image
FROM
(select * from weather where w_date = trunc(sysdate)) w1,
(select * from weather where w_date = trunc(sysdate) + 1) w2,
(select * from weather where w_date = trunc(sysdate) + 2) w3,
(select * from weather where w_date = trunc(sysdate) + 3) w4
UNION ALL
SELECT
w1.w_type, w2.w_type, w3.w_type , w4.w_type
FROM
(select * from weather where w_date = trunc(sysdate)) w1,
(select * from weather where w_date = trunc(sysdate) + 1) w2,
(select * from weather where w_date = trunc(sysdate) + 2) w3,
(select * from weather where w_date = trunc(sysdate) + 3) w4
UNION ALL
SELECT
to_char(w1.high), to_char(w2.high), to_char(w3.high) , to_char(w4.high)
FROM
(select * from weather where w_date = trunc(sysdate)) w1,
(select * from weather where w_date = trunc(sysdate) + 1) w2,
(select * from weather where w_date = trunc(sysdate) + 2) w3,
(select * from weather where w_date = trunc(sysdate) + 3) w4
UNION ALL
SELECT
to_char(w1.low), to_char(w2.low), to_char(w3.low) , to_char(w4.low)
FROM
(select * from weather where w_date = trunc(sysdate)) w1,
(select * from weather where w_date = trunc(sysdate) + 1) w2,
(select * from weather where w_date = trunc(sysdate) + 2) w3,
(select * from weather where w_date = trunc(sysdate) + 3) w4;
/