How to insert duplicate record in the same table with only change the date to the next date - oracle

I have a requirement where I need to duplicate the present record with data column update to the next date.
I have table data like below:
cobdate system b_id b_type L_TYPE lode symbol
------------------------------------------------------------
20150205 M N1 F L P T
20150205 M N1 F L P E
20150205 M N1 F L P E
I want to insert the same data for the next day in the same table.
After insertion I want the data in the table to be like below:
cobdate system b_id b_type L_TYPE lode symbol
-------------------------------------------------------------
20150206 M N1 F L P T
20150206 M N1 F L P E
20150206 M N1 F L P E

Because cobdate is a number, you need to transform it to date, add one day(date operation), then tranform it back to number:
insert into table(
cobdate,
system,b_id, b_type, L_TYPE, lode, symbol
)
select
to_char(to_date(cobdate,'yyyymmdd')+1,'yyyymmdd'),
system,b_id, b_type, L_TYPE, lode, symbol
from table
where cobdate='20150205';
However, you should take note that dates should be stored as DATE, not numbers, not varchars, nor spreaded on three or more columns(ex year, month, day).

Obligatory chiding: You should store dates as DATEs, not as NUMBERs. That said, to add one day to a date stored as a number should not be difficult:
INSERT INTO mytable ( cobdate, system, b_id, b_type, l_type, lode, symbol )
SELECT TO_NUMBER( TO_CHAR( TO_DATE(cobdate, 'YYYYMMDD') + 1, 'YYYYMMDD' ) )
, system, b_id, b_type, l_type, lode, symbol
FROM mytable
WHERE cobdate = 20150205;

Related

add values from other table using cursor in oracle

I am trying to execute the following steps:
Let's say we have a table t1
CREATE TABLE t1 (i1 varchar2,d1 varchar2,l1 varchar2, h1 number(1),q1 number, s1 date );
insert into t1 values('123','1','123-1',0,0,sysdate);
insert into t1 values('123','1','234-1',0,0,sysdate+2);
insert into t1 values('456','2','345-1',0,0,sysdate);
insert into t1 values('456','2','456-1',0,0,sysdate+2);
CREATE TABLE t2 (i2 varchar2,d2 varchar2,q2 number,a2 date );
insert into t2 values('123','1','1230',sysdate);
insert into t2 values('123','1','2340',sysdate+1);
insert into t2 values('456','2','3450',sysdate);
insert into t2 values('456','2','4560',sysdate+1);
Now I have to order t1 data in ascending order of s1 for same i1 and d1 and then check with a2 column of t2. If a2>=s1 but a2< next greater value of s1 then add q2 and assign it to q1.
I am trying to write a cursor which will take values from t1 in ascending order of s1,
for t2.a2>=s1 and t2.a2<s2 --s2 is next greater date value of t1.s1 column
q1 = q1+q2;
I am unable to find an efficient way to do this.
my cursor is:
cursor c1 is (select * from(select i1,d1,s1,min(s1) from t1 where h1=0
group by i1,d1,s1 order by i1,d1,s1));
declare
v_s
v_i
v_d
v_s1
v1 date;
v_q number;
begin
open c1;
fetch c1 into v_i,v_d,v_s,v1;
loop
select s1 into v_s1
from t1 t
where t.i1 = v_i and t.d1=v_d and t.s1>v_s;
select sum(t2.q2) into v_q
from t2 t
where t2.i1=v_i and t2.d2=v_d and t2.a2>=v_s and t2.a2<v_s1;
update t1 set q1 = v_q;
end loop;
close c1;
end;
I want q1 to be populated with sum(q2) for all a2 dates if a2 falls between min and max(s1).
I am unable to execute this. I either keep getting no data found or too many rows fetched or some other error. How can I do this efficiently?
Since you have not shared the end result, I think you want rows 2 & 4 to be null for column Q1. You can try the below co-related sub query to achieve the desired result -
UPDATE t1
SET Q1 = (SELECT SUM(q2)
FROM (SELECT t2.*, a2 - lag(a2) over(partition by i2, d2 order by a2) date_diff
FROM t2) t2
WHERE t1.i1 = t2.i2
AND t1.d1 = t2.d2
AND t1.s1 <= t2.a2
AND NVL(date_diff, 1) = 1);
Demo.

How to Update value in one table by coping it from another table in plsql ?

This is a simple example of what I need to do. In fact I want to Update value in one table by coping it from another table by using cursors in plsql.
I take table f and table b as two examples:
f=
1|Thom
2|Bob
3|Steven
5|Arthur
b=
7|Nataly
9|Alfred
, where I need to insert the b 's tow lines in first f two lines:
create table f (a number, b varchar2(10));
insert into f values (1,'Thom');
insert into f values (2,'Bob');
insert into f values (3,'Steven');
insert into f values (5,'Arthur');
commit;
create table b (c number, d varchar2(10));
insert into b values (7,'Nataly');
insert into b values (9,'Alfred');
commit;
create or replace procedure wco as
cursor c_f is
select a,b from f for update;
v_a f.a%type;
v_b f.b%type;
cursor c_b is
select c,d from b;
v_c b.c%type;
v_d b.d%type;
begin
open c_f;
open c_b
loop
fetch c_f into v_a, v_b;
exit when c_f%ROWCOUNT=c_b%RROWCOUNT;
update f set a=v_c and b=v_d where current of c_f;
end loop;
close c_d:
close c_f;
end;
/
exec wco;
select * from f;
drop table f;
The expected result (What i hope to have):
7|Nataly
9|Alfred
3|Steven
5|Arthur
But what I have now (as a result)is:
1|Thom
2|Bob
3|Steven
5|Arthur
How do I resolve this problem, I am a beginner with PLSQL, I would be very grateful if you could help me please.
Your procedure compiles, but with errors;
In order to see compilation errors
run show errors; after compilation.
Change open c_b to open c_b; (missing semicolon at the end)
Change close c_d: to close c_b; (correct name is c_b and semicolon instead of colon)
Change exit when c_f%ROWCOUNT=c_b%RROWCOUNT; to exit when c_f%ROWCOUNT=c_b%ROWCOUNT; (wrong %RROWCOUNT;)
update f set a=v_c and b=v_d where current of c_f; This is wrong SQL syntax.
Should be update table_name set column=value, column=value;
It is important to provide descriptive names to your variables, so it would be easier to understand your logic.
As I understood you want to copy only second two rows from source table.
create table source_table (
id number,
name varchar2(10));
/
insert into source_table values (1,'Thom');
insert into source_table values (2,'Bob');
insert into source_table values (3,'Steven');
insert into source_table values (5,'Arthur');
/
create table target_table (
id number,
name varchar2(10));
/
insert into target_table values (7,'Nataly');
insert into target_table values (9,'Alfred');
/
create or replace procedure copy_tables
AS
begin
FOR source_row IN (select id, name
from source_table
offset 2 rows)
LOOP
insert into target_table
values(source_row.id, source_row.name);
END LOOP;
end;
/
exec copy_tables;
/
select id, name from target_table;
/
You don't need PL/SQL for this; it can be achieved in a single MERGE statement:
merge into f tgt
using (select coalesce(b1.id, f1.id) id,
coalesce(b1.name, f1.name) name,
f1.f_rowid
from (select id,
name,
rowid f_rowid,
row_number() over (order by id) rn
from f) f1
full outer join (select id,
name,
row_number() over (order by id) rn
from b) b1
on f1.rn = b1.rn) src
on (tgt.rowid = src.f_rowid)
when matched then
update set tgt.id = src.id,
tgt.name = src.name
where tgt.id != src.id
or tgt.name != src.name
when not matched then
insert (tgt.id, tgt.name)
values (src.id, src.name);
See https://livesql.oracle.com/apex/livesql/file/content_FBPR7YCLFVWO7NGDXTLSP1R97.html for the test details (two examples; the target table has more and has fewer rows than the source table).
If you need to, you could add the above insert into a procedure, e.g.:
create procedure populate_target_table as
begin
merge into f tgt
using (select coalesce(b1.id, f1.id) id,
coalesce(b1.name, f1.name) name,
f1.f_rowid
from (select id,
name,
rowid f_rowid,
row_number() over (order by id) rn
from f) f1
full outer join (select id,
name,
row_number() over (order by id) rn
from b) b1
on f1.rn = b1.rn) src
on (tgt.rowid = src.f_rowid)
when matched then
update set tgt.id = src.id,
tgt.name = src.name
where tgt.id != src.id
or tgt.name != src.name
when not matched then
insert (tgt.id, tgt.name)
values (src.id, src.name);
end;
/

Oracle How to return a string in a particular format

I have one requirement where i want to return output in a particular format based on one column(Idx). In one column we have date range based on that loop should execute.
drop table t_table_test;
create table t_table_test ( ID NUMBER, NM VARCHAR2(4000), VAL VARCHAR2(4000), IDX NUMBER);
select * from t_table_test;
INSERT INTO t_table_test VALUES (1,'CNTRY', 'USA',1);
INSERT INTO t_table_test VALUES (1,'DT', '2017-01-01,2017-01-02',2);
INSERT INTO t_table_test VALUES (1,'PART', 'NA',3);
If Input is below
ID NM VAL IDX
1 CNTRY USA 1
1 DT 2017-01-01,2017-01-02 2
1 PART NA 3
Output should be this will be based on IDX column
CNTRY:USA,DT:2017-01-01,PART:NA?CNTRY:USA,DT:2017-01-02,PART:NA
I/P
ID NM VAL IDX
1 DT 2017-01-01,2017-01-02 1
1 CNTRY USA 2
1 PART NA 3
DT:2017-01-01,CNTRY:USA,PART:NA?DT:2017-01-02,CNTRY:USA,PART:NA
DELETE FROM t_table_test WHERE idx=3;
commit;
O/P DT:2017-01-01,CNTRY:USA?DT:2017-01-02,CNTRY:USA
DELETE FROM t_table_test WHERE idx=1;
commit;
O/P DT:2017-01-01?DT:2017-01-02
Need query which work in all above cases .
Perhaps you can try this:
select rtrim(XMLAGG(XMLELEMENT(E,val||'?')).EXTRACT('//text()'),',') from (
with dates as (SELECT distinct NM||':'||trim(regexp_substr(val, '[^,]+', 1, level)) val
from t_table_test where nm='DT' CONNECT BY instr(val, ',', 1, level - 1) > 0),
parts as (select NM||':'||VAL val FROM t_table_test where nm='PART')
SELECT NM||':'||t.VAL||','||d.VAL||','||p.val val from t_table_test t, dates d, parts p
where NM='CNTRY');
It does rely on the names being fixed - having only DT being a comma separated list of values, for instance - but I think it might help you format your results. You can use this as a basis for building many similar formatting solutions.

To split delimited value in column input in where clause

I need to split a column which is Pipe delimited and compare with records. Something like this
select 1
from T1 t1
where t1.date_col not between '01-JAN-2005' and '31-JAN-2005';
I need to fill the between clause value from reference table where the data is something like
ref_table
col_1
01-JAN-2005 | 31-JAN-2005
Query I am trying to achieve
REGEXP_SUBSTR ( col_1
, '^[^|]+') from ref_table
Which is resulting into 01-JAN-2005.
Table T1
date_col
01-Jan-05
15-Jan-05
31-Mar-05
Ref_table
col_1
01-JAN-2005 | 31-JAN-2005
You can do as this:
--Sample data
with t1 as (
select '01-Jan-05' col_1 union
select '15-Jan-05' union
select '31-Mar-05'
),
Ref_table as (
select '01-JAN-2005 | 31-JAN-2005' col_1
)
select *
from t1,
Ref_table r
where to_date(t1.col_1, 'DD/MON/YY')
not between to_date(trim(regexp_replace(r.col_1, '(.*)\|.*', '\1')), 'DD/MON/YY')
and to_date(trim(regexp_replace(r.col_1, '.*\|(.*)', '\1')), 'DD/MON/YY')
Although you really should improve your ref_table design. Store values with some char separated always turns out to be a problem.
Join the dates from table t1 with the intervals from the reference table and subtract the result from the original set of dates:
select t11.date_col
from t1 t11
minus
select t12.date_col
from t1 t12
join (
select to_date ( trim ( substr(col_1, 1, instr(col_1, '|') - 1) ), 'DD-Mon-YYYY' ) d_from
, to_date ( trim ( substr(col_1, instr(col_1, '|') + 1) ), 'DD-Mon-YYYY' ) d_to
from ref_table
) rt on (
rt.d_from <= t12.date_col
AND rt.d_to >= t12.date_col
)
;
I assume that col_1 from your reference table contains the excluded intervals in pairs.

Oracle Pivoting returning Null values for Month/Year

I'm trying to pivoting this table by month/year according to date (field DT):
CREATE TABLE "TEMP"
( "NAME" VARCHAR2(20 BYTE),
"DT" DATE,
"SZ" NUMBER(10,0)
)
Insert into TEMP (NAME,DT,SZ) values ('A',to_date('16/01/15','DD/MM/RR'),'1');
Insert into TEMP (NAME,DT,SZ) values ('B',to_date('16/01/15','DD/MM/RR'),'2');
Insert into TEMP (NAME,DT,SZ) values ('C',to_date('16/01/15','DD/MM/RR'),'3');
Insert into TEMP (NAME,DT,SZ) values ('D',to_date('16/01/15','DD/MM/RR'),'4');
Insert into TEMP (NAME,DT,SZ) values ('A',to_date('10/01/15','DD/MM/RR'),'5');
Insert into TEMP (NAME,DT,SZ) values ('B',to_date('10/01/15','DD/MM/RR'),'6');
Insert into TEMP (NAME,DT,SZ) values ('C',to_date('10/01/15','DD/MM/RR'),'7');
using this query:
SELECT * from
(select name, sz, dt from temp)
pivot (sum(sz) for dt in (to_date('01/2015', 'MM/YYYY') as "dt"))
and I receive this:
NAME dt
-------------------- ----------
D
A
B
C
However, I was excepting to get:
NAME dt
-------------------- ----------
D 4
A 6
B 8
C 10
I've tried many things but none of them seems to work as:
...
pivot (sum(sz) for dt in ('01/2015' as "dt")) --01843. 00000 - "not a valid month"
Do you have a clue of what I'm doing wrong?
Any help is very welcome.
You need to use TO_CHAR and not TO_DATE
WITH pivotdata AS
(
SELECT name,
sz,
To_char(dt, 'MM/YYYY') dt1
FROM temp )
SELECT *
FROM pivotdata pivot (SUM(sz) FOR dt1 IN ('01/2015') );
This will return
NAME '01/2015'
D 4
A 6
B 8
C 10

Resources