Using Oracle merge statement to merge specific rows from a group - sql

Using Oracle database 19c, I'm trying to figure out how to merge only the rows with the most recent date in table1 into table2. If a new row with a matching tab1_id is later added to table1, it should update the row with the matching tab1_id the next time the merge statement is run.
CREATE TABLE table1 (
tab1_id NUMBER(2)
, log_date DATE
, group_name VARCHAR2(10)
, text2 VARCHAR2(10)
, text3 VARCHAR2(10)
, CONSTRAINT pk_tab1 PRIMARY KEY (tab1_id)
);
INSERT INTO table1 VALUES (1, '10-FEB-21', 'group1', 'textrow1', 'textrow1');
INSERT INTO table1 VALUES (2, '09-JAN-21', 'group1', 'textrow2', 'textrow2');
INSERT INTO table1 VALUES (3, '09-MAR-21', 'group1', 'textrow3', 'textrow3');
INSERT INTO table1 VALUES (4, '08-MAR-21', 'group2', 'textrow4', 'textrow4');
INSERT INTO table1 VALUES (5, '08-JAN-21', 'group2', 'textrow5', 'textrow5');
INSERT INTO table1 VALUES (6, '10-FEB-21', 'group2', 'textrow6', 'textrow6');
INSERT INTO table1 VALUES (7, '10-MAR-21', 'group3', 'textrow7', 'textrow7');
INSERT INTO table1 VALUES (8, '05-JAN-21', 'group3', 'textrow8', 'textrow8');
INSERT INTO table1 VALUES (9, '05-FEB-21', 'group3', 'textrow9', 'textrow9');
COMMIT;
CREATE TABLE table2 (
tab2_id NUMBER(2)
, tab1_id NUMBER(2) UNIQUE NOT NULL
, log_date DATE
, group_name VARCHAR2(10)
, text2 VARCHAR2(10)
, text3 VARCHAR2(10)
, CONSTRAINT pk_tab2 PRIMARY KEY (tab2_id)
);
CREATE SEQUENCE seq_table2_id MINVALUE 1 MAXVALUE 99 INCREMENT BY 1 START WITH 1 NOCACHE ORDER NOCYCLE;
These rows should merge into TABLE2 because they contain the most recent date in the log_date column.
edit-(Results should be something like this, ignoring the tab2_id column generated from a sequence.)
TAB2_ID TAB1_ID LOG_DATE GROUP_NAME TEXT2 TEXT3
---------- ---------- --------- ---------- ---------- ----------
1 3 09-MAR-21 group1 textrow3 textrow3
2 4 08-MAR-21 group2 textrow4 textrow4
3 7 10-MAR-21 group3 textrow7 textrow7
Update: based on Caius' comments, I got this to work:
MERGE INTO table2 t2
USING(
WITH T1_TO_MERGE AS (
SELECT
row_number() OVER(
PARTITION BY group_name
ORDER BY log_date DESC
) row_num,
tab1_id,
log_date,
group_name,
text2,
text3
FROM
table1
)
SELECT * FROM T1_TO_MERGE WHERE row_num = 1
) t1
ON(t2.group_name = t1.group_name)
WHEN MATCHED THEN UPDATE
SET t2.tab1_id = t1.tab1_id,
t2.log_date = t1.log_date,
t2.text2 = t1.text2,
t2.text3 = t1.text3
WHEN NOT MATCHED THEN
INSERT(
t2.tab2_id,
t2.tab1_id,
t2.log_date,
t2.group_name,
t2.text2,
t2.text3)
VALUES
(seq_table2_id.NEXTVAL,
t1.tab1_id,
t1.log_date,
t1.group_name,
t1.text2,
t1.text3);
COMMIT;

Related

How make a pivot table using different column as reference?

I don't know how to get this result (see image) if I have this information:
CREATE TABLE TABLE_1
(
FECHA DATE NOT NULL
,LUGAR VARCHAR2(5) NOT NULL
,TIPO_USO VARCHAR2(2) NOT NULL
,NUM_PERSONAS NUMBER
,FORM_PAGO VARCHAR2(255) NOT NULL
);
Insert into TABLE_1 (FECHA,LUGAR,TIPO_USO,NUM_PERSONAS,FORM_PAGO) values (to_date('19/04/01','RR/MM/DD'),'H1','U1','3','tarjeta');
Insert into TABLE_1 (FECHA,LUGAR,TIPO_USO,NUM_PERSONAS,FORM_PAGO) values (to_date('19/04/01','RR/MM/DD'),'H1','U3','2','tarjeta');
Insert into TABLE_1 (FECHA,LUGAR,TIPO_USO,NUM_PERSONAS,FORM_PAGO) values (to_date('19/04/01','RR/MM/DD'),'H1','U4','4','tarjeta');
Insert into TABLE_1 (FECHA,LUGAR,TIPO_USO,NUM_PERSONAS,FORM_PAGO) values (to_date('19/04/02','RR/MM/DD'),'H3','U2','1','ticket');
Insert into TABLE_1 (FECHA,LUGAR,TIPO_USO,NUM_PERSONAS,FORM_PAGO) values (to_date('19/04/02','RR/MM/DD'),'H4','U5','2','ticket');
Insert into TABLE_1 (FECHA,LUGAR,TIPO_USO,NUM_PERSONAS,FORM_PAGO) values (to_date('19/04/02','RR/MM/DD'),'H5','U1','3','tarjeta');
Insert into TABLE_1 (FECHA,LUGAR,TIPO_USO,NUM_PERSONAS,FORM_PAGO) values (to_date('19/04/02','RR/MM/DD'),'H5','U3','2','tarjeta');
Insert into TABLE_1 (FECHA,LUGAR,TIPO_USO,NUM_PERSONAS,FORM_PAGO) values (to_date('19/04/02','RR/MM/DD'),'H5','U4','4','tarjeta');
Insert into TABLE_1 (FECHA,LUGAR,TIPO_USO,NUM_PERSONAS,FORM_PAGO) values (to_date('19/04/03','RR/MM/DD'),'H10','U1','3','tarjeta');
Insert into TABLE_1 (FECHA,LUGAR,TIPO_USO,NUM_PERSONAS,FORM_PAGO) values (to_date('19/04/03','RR/MM/DD'),'H10','U2','1','tarjeta');
Insert into TABLE_1 (FECHA,LUGAR,TIPO_USO,NUM_PERSONAS,FORM_PAGO) values (to_date('19/04/03','RR/MM/DD'),'H12','U3','2','ticket');
CREATE SEQUENCE "SEQ_REPORTE" MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 2206 NOCACHE ORDER NOCYCLE NOKEEP NOSCALE GLOBAL ;
CREATE TABLE TABLE_2 (
ID NUMBER DEFAULT SEQ_REPORTE.nextval NOT NULL
,FECHA DATE NOT NULL
,LUGAR VARCHAR2(5) NOT NULL
,U1 NUMBER
,U2 NUMBER
,U3 NUMBER
,U4 NUMBER
,U5 NUMBER
,FORM_PAGO VARCHAR2(255) NOT NULL
);
i want to get this : (see image)
Can somebody help me?
Thanks so much
Regards
You can try using conditional aggregation
select FECHA,LUGAR,
max(case when TIPO_USO='U1' then NUM_PERSONAS end) as U1,
max(case when TIPO_USO='U2' then NUM_PERSONAS end) as U2,
max(case when TIPO_USO='U3' then NUM_PERSONAS end) as U3,
max(case when TIPO_USO='U4' then NUM_PERSONAS end) as U4,
max(case when TIPO_USO='U5' then NUM_PERSONAS end) as U5,FORM_PAGO
from tablename
group by FECHA,LUGAR,FORM_PAGO

Change column type in table

I have a datatable called deal in Oracle with four columns:
DealID: (PK)
LegID
OrigID
Description
The problem is that if I want to insert a deal with description = A, the attributes LegID and OrigID must be unique, otherwise, there is not problem. How can i make this check? I had thought a trigger after insert. There are more solutions?
Thanks in advance!!
You need a function based unique index :
create table tt (
DealID number(10) primary key,
LegID number(10),
OrigID number(10),
Description varchar2(200 char)
);
create unique index tt_leg_orig_dscr_uk on tt (
case when description = 'A' then description end,
case when description = 'A' then legid end,
case when description = 'A' then origid end
);
insert into tt values (1, 1, 1, 'A');
1 row(s) inserted.
insert into tt values (2, 1, 1, 'A');
ORA-00001: unique constraint (XXXXX.TT_LEG_ORIG_DSCR_UK) violated
insert into tt values (2, 1, 2, 'A');
1 row(s) inserted.
select * from tt;
DEALID LEGID ORIGID DESCRIPTION
-----------------------------------
1 1 1 A
2 1 2 A
2 rows returned in 0.01 seconds
insert into tt values (3, 1, 1, 'B');
1 row(s) inserted.
insert into tt values (4, 1, 1, 'B');
1 row(s) inserted.
select * from tt order by 1;
DEALID LEGID ORIGID DESCRIPTION
-----------------------------------
1 1 1 A
2 1 2 A
3 1 1 B
4 1 1 B
4 rows returned in 0.01 seconds
As you can see, the unique index work only with records with description = 'A', It allows to have non-unique records for different descriptions.

How to select from a table and classify values in oracle/sql

T1:
ID Tag Name
001 [country].[Province] Ontario
002 [Country].[City] Toronto
I want to select values from T1 and insert to another table(T2) and add some values based on province/city;
Sample T2:
Col1 Col2
Ontario Province
Toronto City
Thanks very much!
You may use regexp_substr to retrieve part of the TAG column:
CREATE TABLE t1 (
id VARCHAR2(3),
tag VARCHAR2(40),
name VARCHAR2(40)
);
INSERT INTO t1 VALUES ('001', '[country].[Province]', 'Ontario');
INSERT INTO t1 VALUES ('002', '[country].[City]', 'Toronto');
COMMIT;
CREATE TABLE t2 (
col1 VARCHAR2(40),
col2 VARCHAR2(40)
);
If you are using Oracle 10g:
INSERT INTO t2
SELECT name,
rtrim(
ltrim(
regexp_substr(tag, '[[][a-zA-Z]*[]]', 1, 2),
'['),
']') FROM t1;
If you are using Oracle 11g:
INSERT INTO t2
SELECT name, regexp_substr(tag, '[[]([a-zA-Z]*)[]]', 1, 2, NULL, 1) FROM t1;
Test:
SELECT * FROM t2;
Output:
COL1 COL2
------------------- ----------------------
Ontario Province
Toronto City

how to remove correlated subquery

I'd like to rewrite this query so as not to use the correlated subquery -- but do achieve the same output from the query.
CREATE TABLE "TABLE_1"
( "SITE_ID" NUMBER(*,0),
"USER_ID" NUMBER(*,0),
"REC_ID" NUMBER,
"REPORT_DATE" DATE
) ;
CREATE TABLE "TABLE_2"
( "SITE_ID" NUMBER,
"NOTE_DATE" DATE,
"NOTES" VARCHAR2(2000 BYTE),
"USER_ID" NUMBER,
"REC_ID" NUMBER
) ;
CREATE TABLE "TABLE_3"
( "SITE_ID" NUMBER,
"NOTE_DATE" DATE,
"HELP_NOTES" VARCHAR2(2000 BYTE),
"USER_ID" NUMBER,
"REC_ID" NUMBER
) ;
REM INSERTING into TABLE_1
Insert into TABLE_1 (SITE_ID,USER_ID,REC_ID,REPORT_DATE) values (1,6165,121,to_date('17-APR-10','DD-MON-RR'));
Insert into TABLE_1 (SITE_ID,USER_ID,REC_ID,REPORT_DATE) values (1,6165,121,to_date('01-MAY-10','DD-MON-RR'));
Insert into TABLE_1 (SITE_ID,USER_ID,REC_ID,REPORT_DATE) values (1,6165,121,to_date('08-MAY-10','DD-MON-RR'));
Insert into TABLE_1 (SITE_ID,USER_ID,REC_ID,REPORT_DATE) values (1,6165,121,to_date('24-APR-10','DD-MON-RR'));
Insert into TABLE_1 (SITE_ID,USER_ID,REC_ID,REPORT_DATE) values (1,6165,121,to_date('15-MAY-10','DD-MON-RR'));
Insert into TABLE_1 (SITE_ID,USER_ID,REC_ID,REPORT_DATE) values (1,6165,121,to_date('05-JUN-10','DD-MON-RR'));
Insert into TABLE_1 (SITE_ID,USER_ID,REC_ID,REPORT_DATE) values (1,6165,121,to_date('22-MAY-10','DD-MON-RR'));
Insert into TABLE_1 (SITE_ID,USER_ID,REC_ID,REPORT_DATE) values (1,6165,121,to_date('29-MAY-10','DD-MON-RR'));
REM INSERTING into TABLE_2
Insert into TABLE_2 (SITE_ID,NOTE_DATE,NOTES,USER_ID,REC_ID) values (1,to_date('13-APR-10','DD-MON-RR'),'Notes - we need stuff.',6165,121);
REM INSERTING into TABLE_3
Insert into TABLE_3 (SITE_ID,NOTE_DATE,HELP_NOTES,USER_ID,REC_ID) values (1,to_date('17-MAY-10','DD-MON-RR'),'Entry #1',1932,121);
Insert into TABLE_3 (SITE_ID,NOTE_DATE,HELP_NOTES,USER_ID,REC_ID) values (1,to_date('12-MAY-10','DD-MON-RR'),'Entry #2',6005,121);
Insert into TABLE_3 (SITE_ID,NOTE_DATE,HELP_NOTES,USER_ID,REC_ID) values (1,to_date('25-MAY-10','DD-MON-RR'),'Entry #3',1932,121);
ALTER TABLE "TABLE_1" MODIFY ("REC_ID" NOT NULL ENABLE);
--------------------------------------------------------
-- Constraints for Table TABLE_2
--------------------------------------------------------
ALTER TABLE "TABLE_2" MODIFY ("SITE_ID" NOT NULL ENABLE);
ALTER TABLE "TABLE_2" MODIFY ("REC_ID" NOT NULL ENABLE);
--------------------------------------------------------
-- Constraints for Table TABLE_3
--------------------------------------------------------
ALTER TABLE "TABLE_3" MODIFY ("SITE_ID" NOT NULL ENABLE);
ALTER TABLE "TABLE_3" MODIFY ("REC_ID" NOT NULL ENABLE);
THe query is as follows:
SELECT
TABLE_1.REC_ID,
TO_CHAR(table_1.REPORT_DATE, 'DD-MON-YY HH:MI:SS') report_date,
(
SELECT
MAX(table_3.NOTE_DATE) AS MAX_DATE
FROM
table_3
WHERE
table_3.REC_ID = table_1.REC_ID
AND table_3.NOTE_DATE <= table_1.REPORT_DATE
)
notes_max_date
FROM
table_1
ORDER BY
To_date(table_1.REPORT_DATE, 'DD-MON-YY HH:MI:SS')
And the output should be as follows:
REC_ID REPORT_DATE NOTES_MAX_DATE
---------------------- ------------------ -------------------------
121 17-APR-10 12:30:00
121 24-APR-10 12:30:00
121 01-MAY-10 12:30:00
121 08-MAY-10 12:30:00
121 15-MAY-10 12:30:00 12-MAY-10
121 22-MAY-10 12:30:01 17-MAY-10
121 29-MAY-10 12:30:01 25-MAY-10
121 05-JUN-10 12:30:00 25-MAY-10
8 rows selected
The output needs to be 8 rows and include the nulls in the NOTES_MAX_DATE columm. Thanks!
You could rewrite it with a LEFT JOIN and GROUP BY like this:
SELECT t1.REC_ID
,to_char(t1.REPORT_DATE, 'DD-MON-YY HH:MI:SS') AS report_date
,max(t3.NOTE_DATE) AS notes_max_date
FROM table_1 AS t1
LEFT JOIN table_3 AS t3 ON t3.REC_ID = t1.REC_ID
AND t3.NOTE_DATE <= t1.REPORT_DATE
GROUP BY t1.REC_ID
,to_char(t1.REPORT_DATE, 'DD-MON-YY HH:MI:SS')
ORDER BY to_date(t1.REPORT_DATE, 'DD-MON-YY HH:MI:SS')

Oracle MERGE does not INSERT

I have this simple example I can't seems to get working :
MERGE INTO mytable mt
USING dual
ON (mt.id = 'AAA' )
WHEN MATCHED THEN
UPDATE SET mt.name = 'updated'
WHEN NOT MATCHED THEN
INSERT (mt.id , mt.name )
VALUES ('AAA', 'Gooood' );
If a 'AAA' record exists in the table, it is updated successfully.
But if does not exists, it is not inserted :
Affected rows: 0
Time: 0.003ms
Any clue on what I am doing wrong ?
Works for me:
SQL> create table mytable (id varchar(3), name varchar(30));
Table created.
SQL> MERGE INTO mytable mt
2 USING dual
3 ON (mt.id = 'AAA' )
4 WHEN MATCHED THEN
5 UPDATE SET mt.name = 'updated'
6 WHEN NOT MATCHED THEN
7 INSERT (mt.id , mt.name )
8 VALUES ('AAA', 'Gooood' );
1 row merged.
SQL> select * from mytable;
ID NAME
--- ------------------------------
AAA Gooood