How select from two different tables with multiple foreign keys - sql

First explain what I need using an image:
Second creation tables:
CREATE SEQUENCE SEQ_tab7 MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 2206 NOCACHE ORDER NOCYCLE NOKEEP NOSCALE GLOBAL ;
CREATE SEQUENCE SEQ_tab8 MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 2206 NOCACHE ORDER NOCYCLE NOKEEP NOSCALE GLOBAL ;
CREATE TABLE TABLE_7
(
ID NUMBER(19,0) DEFAULT SEQ_tab7.nextval NOT NULL
,DESCRIPTION VARCHAR2(256) NOT NULL
,CONSTRAINT TAB_7_PK PRIMARY KEY (ID) ENABLE
);
CREATE TABLE TABLE_8
(
ID NUMBER(19,0) DEFAULT SEQ_tab8.nextval NOT NULL
,FIELD_1 NUMBER(19,0) NOT NULL
,FIELD_2 NUMBER(19,0) NOT NULL
,FIELD_3 NUMBER(19,0) NOT NULL
,FIELD_4 VARCHAR2(256)
,CONSTRAINT TAB_8_PK PRIMARY KEY (ID) ENABLE
,CONSTRAINT tab_8_FIELD_1_FK FOREIGN KEY (FIELD_1) REFERENCES TABLE_7(ID)
,CONSTRAINT tab_8_FIELD_2_FK FOREIGN KEY (FIELD_2) REFERENCES TABLE_7(ID)
,CONSTRAINT tab_8_FIELD_3_FK FOREIGN KEY (FIELD_3) REFERENCES TABLE_7(ID)
);
Third - inserts:
Insert into TABLE_7 (ID,DESCRIPTION) values ('1','desc_1');
Insert into TABLE_7 (ID,DESCRIPTION) values ('2','desc_2');
Insert into TABLE_7 (ID,DESCRIPTION) values ('3','desc_3');
Insert into TABLE_8 (ID,FIELD_1,FIELD_2,FIELD_3,FIELD_4) values ('23','1','2','1','lorem_1');
Insert into TABLE_8 (ID,FIELD_1,FIELD_2,FIELD_3,FIELD_4) values ('43','1','3','3','lorem_2');
Insert into TABLE_8 (ID,FIELD_1,FIELD_2,FIELD_3,FIELD_4) values ('54','3','3','3','lorem_3');
How could I get the desired results?
Best regards

Use multiple joins
Try this:
SELECT Base.ID, FirstJoin.Desc, SecondJoin.Desc, ThirdJoin.Desc, Base.field_4
FROM table_2 Base
JOIN table_1 FirstJoin ON FirstJoin.ID = Base.Field_1
JOIN table_1 SecondJoin ON SecondJoin.ID = Base.Field_2
JOIN table_1 ThirdJoin ON ThirdJoin.ID = Base.Field_3

Here is an example which use subqueries for each field_? it will search in table_1 for the description and use it as an attribute. I added alias for the field to make the output more clear.
SELECT
table_2.id,
(SELECT table_1.desc FROM table_1 WHERE table_1.id=table_2.field_1) as "FIELD_1",
(SELECT table_1.desc FROM table_1 WHERE table_1.id=table_2.field_2) as "FIELD_2",
(SELECT table_1.desc FROM table_1 WHERE table_1.id=table_2.field_3) as "FIELD_3",
table_2.field_4
FROM table_2;
For example the first row of table_2 is (id=23, field_1=1, field_2=2, field_3=1, field_4="lorem_1") The second attribute after performing the suggested query will be the result of the query SELECT table_1.desc FROM table_1 WHERE table_1.id=table_2.field_1 which is "desc_1" and the same process for the field_2 and field_3
in that case the result for the first row will be:
ID FIELD_1 FIELD_2 FIELD_3 FIELD_4
23 desc_1 desc_2 desc_1 lorem_1

Related

How to write case expression inside merge statement to print the desired result

CREATE TABLE DELIGATE_DETAILS_MAIN
( E_ID NUMBER(10,0),
COMPLETED_DATE TIMESTAMP (6),
CONSTRAINT PK_DELIGATE_DETAILS_MAIN PRIMARY KEY (E_ID));
Insert into deligate_details_main (E_ID,COMPLETED_DATE) values (1,to_timestamp('13-12-21 6:05:23.991000000 PM','DD-MM-RR fmHH12:fmMI:SSXFF AM'));
Insert into deligate_details_main (E_ID,COMPLETED_DATE) values (2,to_timestamp('13-12-21 6:05:24.019000000 PM','DD-MM-RR fmHH12:fmMI:SSXFF AM'));
Insert into deligate_details_main (E_ID,COMPLETED_DATE) values (3,to_timestamp('13-12-21 6:05:24.029000000 PM','DD-MM-RR fmHH12:fmMI:SSXFF AM'));
Insert into deligate_details_main (E_ID,COMPLETED_DATE) values (4,to_timestamp('13-12-21 10:46:00.015000000 PM','DD-MM-RR fmHH12:fmMI:SSXFF AM'));
CREATE TABLE CONTROL_MAIN
( E_ID NUMBER(10,0),
E_SPEC VARCHAR2(30 BYTE),
CONSTRAINT PK_CONTROL_MAIN PRIMARY KEY (E_ID));
Insert into CONTROL_MAIN (E_ID,E_SPEC) values (1,'SAP1');
Insert into CONTROL_MAIN (E_ID,E_SPEC) values (2,'FSAP');
Insert into CONTROL_MAIN (E_ID,E_SPEC) values (3,'SAP2');
Insert into CONTROL_MAIN (E_ID,E_SPEC) values (4,'SAP1-480');
CREATE TABLE QUESTION
( E_ID NUMBER(10,0),
QUEST VARCHAR2(30 BYTE),
CONSTRAINT PK_QUESTION PRIMARY KEY (E_ID));
Insert into QUESTION (E_ID,QUEST) values (1,'Yes');
Insert into QUESTION (E_ID,QUEST) values (2,'No');
Insert into QUESTION (E_ID,QUEST) values (3,'Yes');
Insert into QUESTION (E_ID,QUEST) values (4,'Yes');
CREATE TABLE DELIGATE_DETAILS_TRANS
( D_ID NUMBER(10,0),
E_ID NUMBER(10,0),
COMPLETED_DATE_TRANS DATE,
OWNER_DETAIL VARCHAR2(30 BYTE),
CONSTRAINT PK_DELIGATE_DETAILS_TRANS PRIMARY KEY (D_ID),
CONSTRAINT FK_E_ID FOREIGN KEY (E_ID)
REFERENCES TAM.DELIGATE_DETAILS_MAIN (E_ID));
Attempt:
MERGE INTO deligate_details_trans t USING ( SELECT
ddm.e_id,
ddm.completed_date
FROM
deligate_details_main ddm
JOIN control_main cm ON ( cm.e_id = ddm.e_id AND cm.e_spec LIKE %'SAP'% )
JOIN question q ON ( q.e_id = ddm.e_id
AND q.quest = 'Yes' )
) s
on (t.e_id = s.e_id)
when not matched then
insert (d_id,e_id, completed_date_trans, owner_detail)
values (
deligate_details_trans_sq.nextval,
s.e_id,
CAST(s.completed_date AS DATE),
--Here need to insert owner detail from control main
--If it is SAP1 or SAP2 then it will insert SAP1 or SAP2
--If it is SAP1-480 then it should insert SAP3);
Expected output:
+------+---------+-----------------------+--------------+
| D_ID | E_ID | COMPLETED_DATE_TRANS | OWNER_DETAIL |
+------+---------+-----------------------+--------------+
| 1 | 1 | 13-12-21 | SAP1 |
| 2 | 3 | 13-12-21 | SAP2 |
| 3 | 4 | 13-12-21 | SAP3 |
+------+---------+-----------------------+--------------+
For e_id 1: Based on the join condition from control_main and question table. Data should get inserted into the deligate_details_trans table and owner detail should be SAP1.
For e_id 2: Based on the join condition from control_main and question table. Data is NOT matching so it should not get inserted into the trans table.
For e_id 3: Based on the join condition from control_main and question table. Data should get inserted into the deligate_details_trans table and owner detail should be SAP2.
For e_id 4 it should check in the control main table and if it is SAP1-480 then it should insert SAP3 and for others, corresponding owner details should be inserted from the control_main table
If you want the case expression in the insert's values clause then you need to expose the control table value in the using clause:
MERGE INTO deligate_details_trans t
USING (
SELECT
ddm.e_id,
ddm.completed_date,
cm.e_spec
FROM
deligate_details_main ddm
JOIN control_main cm ON ( cm.e_id = ddm.e_id AND cm.e_spec LIKE '%SAP%' )
JOIN question q ON ( q.e_id = ddm.e_id
AND q.quest = 'Yes' )
) s
ON (t.e_id = s.e_id)
WHEN NOT MATCHED THEN INSERT (
d_id,e_id, completed_date_trans, owner_detail
)
VALUES (
deligate_details_trans_sq.nextval,
s.e_id,
CAST(s.completed_date AS DATE),
CASE s.e_spec
WHEN 'SAP1' THEN 'SAP1'
WHEN 'SAP2' THEN 'SAP2'
WHEN 'SAP1-480' THEN 'SAP3'
END
);
Alternatively move the case expression into the using clause, give it an alias, and refer to that alias in the values clause:
MERGE INTO deligate_details_trans t
USING (
SELECT
ddm.e_id,
ddm.completed_date,
CASE cm.e_spec
WHEN 'SAP1' THEN 'SAP1'
WHEN 'SAP2' THEN 'SAP2'
WHEN 'SAP1-480' THEN 'SAP3'
END AS owner_detail
FROM
deligate_details_main ddm
JOIN control_main cm ON ( cm.e_id = ddm.e_id AND cm.e_spec LIKE '%SAP%' )
JOIN question q ON ( q.e_id = ddm.e_id
AND q.quest = 'Yes' )
) s
ON (t.e_id = s.e_id)
WHEN NOT MATCHED THEN INSERT (
d_id,e_id, completed_date_trans, owner_detail
)
VALUES (
deligate_details_trans_sq.nextval,
s.e_id,
CAST(s.completed_date AS DATE),
s.owner_detail
);
db<>fiddle showing both (with %'SAP'% changed to '%SAP%', and sequence creation added).
I'm not sure why you have a timestamp in one table and a date in the other, and you don't need an explicit cast (though it doesn't hurt). But if you're doing that because you're only interested in the date part you should be aware that an Oracle date still has a time component, even if it isn't being shown in your DD-MM-YY format or db<>fiddle's default DD-MON-YY format. If you want to 'lose' the time part you can truncate the value at the day (DD) component, shown in this db<>fiddle which changes the display format so you can see the difference. But you might want to keep the time - in which case, ignore this part...

Transfer data from one table to another with both table having same id, in Postgres

I have 2 tables. TBL_A and TBL_B. I want to update TBL_A so that A_NAME = B_NAME, where A_LA = B_LA. How do I do this? This is just s sample data. In the real table, I have thousands of records on each table.
I tried connecting both tables using View, but it seems that the view can't be updated.
TBL_A:
CREATE TABLE public."TBL_A"
(
"A_LA" character varying,
"A_NAME" character varying,
"A_ID" bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 1000 CACHE 1 ),
CONSTRAINT "TBL_A_pkey" PRIMARY KEY ("A_ID")
);
INSERT INTO public."TBL_A"("A_LA", "A_NAME") VALUES ('8904001', '');
INSERT INTO public."TBL_A"("A_LA", "A_NAME") VALUES ('8904003', '');
INSERT INTO public."TBL_A"("A_LA", "A_NAME") VALUES ('8904005', '');
TBL_B:
CREATE TABLE public."TBL_B"
(
"B_LA" character varying,
"B_NAME" character varying,
"B_ID" bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 1000 CACHE 1 ),
CONSTRAINT "TBL_B_pkey" PRIMARY KEY ("B_ID")
);
INSERT INTO public."TBL_B"("B_LA", "B_NAME") VALUES ('8904001', 'John');
INSERT INTO public."TBL_B"("B_LA", "B_NAME") VALUES ('8904002', 'James');
INSERT INTO public."TBL_B"("B_LA", "B_NAME") VALUES ('8904003', 'Jacob')
INSERT INTO public."TBL_B"("B_LA", "B_NAME") VALUES ('8904004', 'Jared')
INSERT INTO public."TBL_B"("B_LA", "B_NAME") VALUES ('8904005', 'Josh');
View:
CREATE VIEW public."A_B_CONNECT_VIEW" AS
SELECT "TBL_A"."A_LA","TBL_A"."A_NAME","TBL_B"."B_LA","TBL_B"."B_NAME"
FROM "TBL_A" JOIN "TBL_B" ON "TBL_A"."A_LA"::text = "TBL_B"."B_LA"::text;
You can do it in this way:
UPDATE table_A AS A
SET A.A_NAME = B.B_NAME
FROM table_B AS B
WHERE A.A_LA = B.B_LA;
I update the query from #Farshid Shekari for it to work.
UPDATE "TBL_A" AS A
SET "A_NAME" = B."B_NAME"
FROM "TBL_B" AS B
WHERE A."A_LA" = B."B_LA";

Conditional Unique Constraint, Ignored for Same Foreign Key

I have a situation where I need to maintain a unique constraint for two columns (FK_1, NAME) conditionally. The constraint should not apply for rows where a second foreign key is the same (FK_2).
ID FK_1 FK_2 NAME
1 2 3 'X01'
2 2 3 'X01-A'
3 2 3 'X01' --Accepted
4 2 4 'X01' --Violation
5 3 5 'X01' --Accepted
What I'm trying to accomplish is that rows 1, 2, and 3 are valid, because FK_2 is the same. They break the unique constraint, but the unique constraint is ignored because FK_2 is the same. Row 4 will violate the unique constraint for (FK_1,NAME) because FK_2 would have been new. And finally, row 5 is fine due to the normal function of a unique constraint on (FK_1,NAME).
It's trying to determine how to handle row 3 that is the complication.
I've seen several examples of how to address this same problem when the equivalent of FK_2 is hard-coded to some extent (Oracle: function based index selective uniqueness), but I'm not sure how I can address this for a foreign key, where I really don't have control over the value of FK_2.
I have tried implementing a function-based unique index, but it results in a ORA-04091 exception.
CREATE OR REPLACE FUNCTION UNQ_TEST_FUNCTION(var_fk_1 IN NUMBER, var_fk_2 IN NUMBER, var_name IN VARCHAR2) RETURN NUMBER DETERMINISTIC IS
result NUMBER;
BEGIN
result := null;
IF (var_fk_1 IS NULL OR var_fk_2 IS NULL OR var_name IS NULL ) THEN
result := null;
ELSE
SELECT COUNT(ID) INTO result FROM TEST1 WHERE
FK_2 != var_fk_2 AND FK_1 = var_fk_1 AND NAME = var_name;
IF (result <= 0) THEN
result := null;
ELSE
result := 1;
END IF;
END IF;
RETURN result;
END;
CREATE UNIQUE INDEX UNQ_TEST ON TEST1
(
UNQ_TEST_FUNCTION("FK_1","FK_2","NAME")
)
;
INSERT INTO TEST1 (ID, FK_1, FK_2, NAME)
VALUES (1, 2, 3, 'X01');
ORA-04091: table TEST1 is mutating, trigger/function may not see it
The exception makes perfect sense, but being unable to query the table puts me at a loss about where to go.
An interesting problem. I would approach this in the following way:
CREATE TABLE t123_fk(
FK_1 int,
FK_2 int,
CONSTRAINT t123_fk_pk PRIMARY KEY(FK_1, FK_2),
CONSTRAINT fk_2_is_new_constr_violated UNIQUE(FK_1)
);
CREATE TABLE t123(
ID int,
FK_1 int,
FK_2 int,
NAME varchar2(100),
constraint t123_fk FOREIGN KEY(FK_1, FK_2) REFERENCES t123_fk
);
CREATE OR REPLACE TRIGGER some_name
BEFORE INSERT OR UPDATE ON t123
FOR EACH ROW
BEGIN
INSERT INTO t123_fk( fk_1, fk_2 )
SELECT :new.FK_1, :new.FK_2 FROM dual
WHERE NOT EXISTS(
SELECT 1 FROM t123_fk
WHERE fk_1 = :new.fk_1 AND fk_2 = :new.fk_2
);
END;
/
Table t123 is the main table containing our data.
Table t123_fk and the trigger are auxiliary and they are used only to help us to force our constraint (btw, our constraint is named fk_2_is_new_constr_violated in the above code).
Here is a test - the fourth insert will be rejected by the database:
insert into t123( id, fk_1, fk_2, name) values(1,2,3,'X01');
insert into t123( id, fk_1, fk_2, name) values(2,2,3,'X01-A');
insert into t123( id, fk_1, fk_2, name) values(3,2,3,'X01');
insert into t123( id, fk_1, fk_2, name) values(4,2,4,'X01'); // this insert will be rejected
insert into t123( id, fk_1, fk_2, name) values(5,3,5,'X01');

Oracle Update takes long time while updating primary key column

There is the table EFORMDYNAMICFIELDINSTANCE with primary key (Enterpriseid, Ownertype, Ownerid, Itemtype, Itemid).
In order to change a primary key to single column i.e EDFI_ID we want to update this EDFI_ID starting with 7000000 as increment value.
This table with hardly 50000 records takes 10 hrs to update.
This is my table defination:
ENTERPRISEID NOT NULL NUMBER(10),
OWNERTYPE NOT NULL VARCHAR2(60),
OWNERID NOT NULL NUMBER(10),
ITEMTYPE NOT NULL VARCHAR2(60),
ITEMID NOT NULL NUMBER(10),
EDFI_ID NOT NULL NUMBER(10),
FIELD1 VARCHAR2(2000),
FIELD2 VARCHAR2(2000),
...
FIELD199 VARCHAR2(2000),
FIELD200 VARCHAR2(2000)
Earlier we had (ENTERPRISEID, OWNERTYPE, OWNERID, ITEMTYPE, ITEMID) as the primary key.
Now EDFI_ID is my primary key column and we want to update this primary key with (rownumber + 7000000). This table has approximately 50000 records and EDFI_ID should update as 7000000, 7000001, 7000002....7050000.
Please suggest an UPDATE statement which will take less time. As of now my above UPDATE is taking 10 hours.
My guess is that your problem is the repeated execution of your subqueries. I'm not even sure the second one (inside the WHERE EXISTS) is doing anything useful.
Strip out the WHERE EXISTS - that will eliminate half the effort. If that doesn't help then...
create a temporary mapping table that holds all your existing primary key values, along with your new PK value. Create a unique index on your five PK columns. Then use the mapping table in the subquery
Just to elaborate on my second suggestion :
CREATE TABLE temp_pk_mapping AS
(SELECT
enterpriseid
,ownertype
,ownerid
,itemtype
,itemid
,rownum + 70000 new_pk
FROM
(SELECT DISTINCT
enterpriseid
,ownertype
,ownerid
,itemtype
,itemid
FROM
eformdynamicfieldinstance
)
)
;
CREATE UNIQUE INDEX temp_pk_mapping_u1 ON temp_pk_mapping
( enterpriseid
,ownertype
,ownerid
,itemtype
,itemid
)
;
UPDATE eformdynamicfieldinstance edfi
SET edfi.edfi_id =
(SELECT new_pk
FROM temp_pk_mapping map
WHERE edfi.enterpriseid = map.enterpriseid
AND edfi.ownertype = map.ownertype
AND edfi.ownerid = map.ownerid
AND edfi.itemtype = map.itemtype
AND edfi.itemid = map.itemid
)
;

Insert multiple rows with one column from another table

I have two tables
CREATE TABLE table1 (
id bigint NOT NULL,
name character varying(255),
CONSTRAINT table1_pkey PRIMARY KEY (id)
);
CREATE TABLE table2 (
id bigint NOT NULL,
name character varying(255),
table1_id bigint,
CONSTRAINT table2_pkey PRIMARY KEY (id),
CONSTRAINT fk_table1_table2 FOREIGN KEY (table1_id)
REFERENCES table1 (id) MATCH SIMPLE
);
now what i want to do is for each entry in table1 add entry in table2
ie if my table 1 has entries
|id | name |
|1 | First |
|2 | Second |
|3 | Third |
I need to create three entries in table2
insert into table2 (id,name,table2_id) values (nextval('table2_seq'),'new entry', 1);
insert into table2 (id,name,table2_id) values (nextval('table2_seq'),'new entry', 2);
insert into table2 (id,name,table2_id) values (nextval('table2_seq'),'new entry', 3);
and as only foreign key is changed for each new entry, i was wonder is it any possibility to automate this process.
Is it possible to achieve with query, or should i look at procedures?
Use an insert based on a select:
insert into table2 (id,name,table1_id)
select nextval('table2_seq'), 'new entry', t1.id
from table1;
I struggled to get a "SELECT ... WHERE" in the subquery, likely not enough coffee, but finalised on the below syntax:
insert into table (col1, col2 ...)
select 'staticval1',
r.variable1 from reftable r where r.variable2 = 'Some search term'
...;