What is the correct order in which tables should be joined - oracle

I have three tables
TABLE 1
PLANS -> Has all the plans information
COLUMNS:
PLAN_ID
PLAN_NAME
OTHER_DETAILS
(PLAN_ID is the PRIMARY KEY)
TABLE 2
REGISTER ->
COLUMNS:
RUN_ID
PLAN_ID
REGISTER_DETAILS
(RUN_ID AND PLAN_ID) is the primary key
TABLE 3
ELECTION ->
Columns
RUN_ID
PLAN_ID
ELECTION_DETAILS
(RUN_ID AND PLAN_ID) is the primary key
PLAN_ID could be present in either REGISTER (or) ELECTION (or) BOTH tables.
For an input RUN_ID , I need to pick rows in the below format such that if a plan has only register details only REGISTER_DETAILS is picked.
If a plan has both REGISTER_DETAILS and ELECTION_DETAILS then both the details should get returned.
Report Format:
RUN_ID PLAN_ID REGISTER_DETAILS ELECTION_DETAILS
Solution
I tried by joining the tables in below format:
SELECT
..
FROM
PLANS A
LEFT JOIN REGISTER B
ON (A.PLAN_ID = B.PLAN_ID
AND B.RUN_ID = 'Input Run Id')
LEFT JOIN ELECTION C
ON (A.PLAN_ID = C.PLAN_ID
AND C.RUN_ID = 'Input Run Id')
But this is also returning plans that are not present in REGISTER and ELECTION tables.
Can someone please tell what is wrong with the query?

Add
WHERE B.PLAN_ID IS NOT NULL OR
C.PLAN_ID IS NOT NULL
to the end of your query.
Best of luck.

Related

Spring JPA: Need to join two table with dynamic clauses

Requirement is as below:
Table 1 - Order(ID, orderId, sequence, reference, valueDate, date)
Table 2 - Audit(AuditId, orderId, sequence, status, updatedBy, lastUpdatedDateTime)
For each record in ORDER table, there could be one or many rows in AUDIT table.
User is given a search form where he could enter any of the search params including status from audit table.
I need a way to join these two tables with dynamic where clause and get the top row for a given ORDER from AUDIT table.
Something like below:
select * from
ORDER t1, AUDIT t2
where t1.orderid = t2.orderId
and t1.sequence = t2.sequence
and t2.status = <userProvidedStatusIfAny>
and t2.lastUpdatedDateTime in (select max(t3.lastUpdatedDateTime) --getting latest record
AUDIT t3 where t1.orderid = t3.orderId
and t1.sequence = t3.sequence)
and t1.valudeDate = <userProvidedDataIfAny> ..... so on
Please help
-I cant do this with #Query because i have to form dynamic where clause
-#OneToMany fetches all the records in audit table for given orderId and sequence
-#Formula in ORDER table works but for only one column in select. i need multiple values from AUDIT table
Please help

SQL Foreign key to two different tables

I have a problem like
Table A:
-- TableBCId
Table B:
-- Id
Table C:
-- Id
I am looking for a way to create a foreign key table A where an entry can be either in table B or table C
Example entries:
Table A:
-- TableBCId: 1
-- TableBCId: 2
Table B:
-- Id: 1
Table C:
-- Id: 2
I want to avoid if possible:
- Two columns in table A
- Default values
- Additional tables
- Creation of an base entity is not possible
Every idea welcome
The normal way to implement this requirement is with 2 columns, 2 foreign key constraints, and a check constraint to ensure exactly of of the columns populated (if this is a requirement):
create table a
( ...
, b_id references b
, c_id references c
, constraint <name> check ( (b_id is null and c_id is not null)
or (b_id is not null and c_id is null)
)
);
You could, if it helps your UI, create a view over that table that combines B_ID and C_ID into a single column.
But you have said you don't want 2 columns, why is that?
The reason why this is hard is because the data model is wrong. A foreign key references only one table. A table can have more than one foreign key but each is separate. Apart from anything else, how would you know whether bc_id referenced b.id or c.id?
One explanation for this scenario is that table A should really be two tables, BA referencing B and CA referencing C. Alternatively A should reference a super-type table, of which B and C are sub-types. Without knowing the actual business domain it's hard to be sure.
Anyway, the path of least change is two columns.
You can use a insert/update trigger on your Table_A.
Maybe something like this:
CREATE TRIGGER Table_a_trgr
BEFORE INSERT OR UPDATE
on Table_a
FOR EACH ROW
DECLARE
c_row NUMBER;
BEGIN
SELECT count(*)
INTO c_row
FROM (
SELECT ID FROM table_b WHERE id = :NEW.TableBCId
UNION ALL
SELECT ID FROM table_c WHERE İd = :NEW.TableBCId
)
;
IF c_row < 2 THEN
raise_application_error(-20000, 'Error, Foreign Key');
END IF;
END;
/
If you don't want to make a new column in table A.
Then you can make a parent table to B and C.
tableBC:
id
And then create a 1-1 relation with tables B and C to table BC.
tableB:
id,
parent -- 1-1 foreign key to tableBC
tableC:
id,
parent -- 1-1 foreign key to tableBC
Now, in table A
tableA:
id,
TableBCId -- foreign key to tableBC
We have solved a similar problem using this approach.

Update with 2 joins

I'm trying to update data in 2 distinct tables in the same query with the following code:
UPDATE (SELECT s.passNumb, a.hour, a.minute, p.number, s.situation
FROM passwords s
JOIN atend a ON s.passNumb = a.passNumb
JOIN points p ON a.number = p.number
WHERE s.passNumb = 1 AND
p.number = 1)
SET a.hour = TO_CHAR(SYSDATE, 'HH24'),
a.minute = TO_CHAR(SYSDATE, 'MI'),
s.situation = 'F';
But I'm getting this error: Cannot modify a column which maps to a non key-preserved table. What am I doing wrong?
A view with a join (or an inline view containing a join in your case) must meet the following conditions to be updatable:
https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_8004.htm
If you want a join view to be updatable, then all of the following
conditions must be true:
The DML statement must affect only one table underlying the join.
For an INSERT statement, the view must not be created WITH CHECK
OPTION, and all columns into which values are inserted must come from
a key-preserved table. A key-preserved table is one for which every
primary key or unique key value in the base table is also unique in
the join view.
For an UPDATE statement, the view must not be created WITH CHECK
OPTION, and all columns updated must be extracted from a key-preserved
table.
The first condition is rather obvious: The DML statement must affect only one table underlying the join.
But what does it mean: "key preserved table" ?
A key-preserved table is one for which every primary key or unique
key value in the base table is also unique in the join view.
The key preserved table means that each row from this table will appear at most once in the result of a view.
Consider a simple example:
CREATE TABLE users(
user_id int primary key,
user_name varchar(100),
age int
);
insert into users values(1,'Tom', 22);
CREATE TABLE emails(
user_id int,
email varchar(100)
);
Insert into emails values( 1, 'tom#somedomain.com' );
Insert into emails values( 1, 'tom#www.example.org' );
commit;
And a join:
SELECT *
FROM users u
JOIN emails e ON u.user_id = e.user_id;
USER_ID USER_NAME AGE USER_ID EMAIL
---------- --------------- ---------- ---------- --------------------
1 Tom 22 1 tom#somedomain.com
1 Tom 22 1 tom#www.example.org
If you look at a result of this join, it is apparent that:
user_id, user_name and age come from non-key preserved table
email comes from key-preserved table
And now: this update is acceptable, because it updates a key preserved column (table) in this join:
UPDATE (
SELECT * FROM users u
JOIN emails e ON u.user_id = e.user_id
)
SET email = email || '.it' ;
USER_ID USER_NAME AGE USER_ID EMAIL
---------- --------------- ---------- ---------- -------------------------
1 Tom 22 1 tom#somedomain.com.it
1 Tom 22 1 tom#www.example.org.it
But this update cannot be done, since it touches a column from non-key preserved table:
UPDATE (
SELECT * FROM users u
JOIN emails e ON u.user_id = e.user_id
)
SET age = age + 2;
SQL Error: ORA-01779: cannot modify a column which maps to a non key-preserved table
01779. 00000 - "cannot modify a column which maps to a non key-preserved table"
*Cause: An attempt was made to insert or update columns of a join view which
map to a non-key-preserved table.
*Action: Modify the underlying base tables directly.
If you think a while .... Tom appears 2 times in the result of the join (but there is only one Tom in the users table).
When we are trying to update age = age + 2 in this join, then what should be a result of this update ?
Should Tom be updated only once ?
Should Tom be 22+2 = 24 years old after this update ?
Or maybe Tom should be updated twice (since it appears twice in the result of the join) so it should be 22 + 2 + 2 = 26 years old.
Another example - please tell me what should be an outcome of this update?:
UPDATE ( ....our join ... ) SET age = length( email );
There are very difficult questions :)
And because of this Oracle prevents from updating non-key preserved tables.
The error message gives this hint:
*Action: Modify the underlying base tables directly.
This means that we must update this table directly, using a separate UPDATE command:
UPDATE users SET age = age + 2

Trigger Before Insert on multiple tables

I am fairly new to triggers and PL/SQL, so my question is mainly one of design.
I am creating a set of tables to represent ticket purchases. There are three types of tickets:
Ticket #1: Price, Quantity, Time
Ticket #2: Price, Quantity, Time, Seating, Refundable
Ticket #3: Price, Quantity, Time, Food , Drink
So I have created three tables: (I believe this is called, normalizing):
Table1 has columns Price, Quantity and Time
Table2 has Seating and Refundable
Table3 has Food and Drink
I have inserted a primary key column into Table1 and am using foreign keys in Table2 and Table3 which point to Table1's PK.
The Plan: When a user purchases a ticket, I insert a record into the appropriate table(s). For instance, if the user purchases:
Ticket #1, I insert a record into Table1
Ticket #2, I insert a record into Table1 and Table2
Ticket #3, I insert a record into Table1 and Table3
The Problem: How can I receive all the data for a ticket not of type 1, and then split the parameters to insert into the separate tables. For instance, when I try to create a trigger for Table2, that trigger can only receive the parameters that match what Table2 columns has. How can I receive the data for Table1?
An example of a complete purchase of ticket type 2.
User purchases ticket online -> web form stuff happends... -> dao sends ONE insert command to the database -> trigger for Table2 kicks off and validates info for Table1 and Table2.
Thanks!
You can design this in any way you want, but given that there's not much difference between the ticket types I'd have a single table:
CREATE TABLE TICKET
(ID_TICKET NUMBER
CONSTRAINT PK_TICKET
PRIMARY KEY
USING INDEX,
TICKET_TYPE NUMBER
NOT NULL
CONSTRAINT TICKET_CK1
CHECK(TICKET_TYPE IN (1, 2, 3)),
PRICE NUMBER
NOT NULL,
QUANTITY NUMBER
NOT NULL,
DEPARTURE_TIME DATE
NOT NULL,
SEATING NUMBER
CONSTRAINT TICKET_CK2
CHECK(1 = CASE TICKET_TYPE
WHEN 1 THEN CASE
WHEN SEATING IS NULL
THEN 1
ELSE 0
END
WHEN 2 THEN CASE
WHEN SEATING IS NULL
THEN 0
ELSE 1
END
WHEN 3 THEN CASE
WHEN SEATING IS NULL
THEN 1
ELSE 0
END
END),
REFUNDABLE_INDC CHAR(1)
NOT NULL
CONSTRAINT TICKET_CK3
CHECK(REFUNDABLE_INDC = CASE TICKET_TYPE
WHEN 1 THEN 'N'
WHEN 2 THEN 'Y'
WHEN 3 THEN 'N'
END),
FOOD CHAR(1)
NOT NULL
CONSTRAINT TICKET_CK4
CHECK(FOOD = CASE TICKET_TYPE
WHEN 1 THEN 'N'
WHEN 2 THEN 'N'
WHEN 3 THEN 'Y'
END),
DRINK CHAR(1)
NOT NULL
CONSTRAINT TICKET_CK5
CHECK(DRINK = CASE TICKET_TYPE
WHEN 1 THEN 'N'
WHEN 2 THEN 'N'
WHEN 3 THEN 'Y'
END));
Here CHECK constraints are used to ensure that only the appropriate fields are filled in, based on the ticket type.
Best of luck.

Joining 3 tables in Oracle

I need to join three tables in Oracle; I have code but I am not sure if it is totally right.
FROM DISTRICT D1
JOIN EMPLOYEE E1 ON D1.DISTRICT_ID = E1.DISTRICT_ID
JOIN TOTAL_PAB T1 ON E1.EMP_ID = T1.EMP_ID
I need to join the table DISTRICT, EMPLOYEE, AND TOTAL_PAB.
Where do the primary and foreign keys go in this join table statement?
Primary key for EMPLOYEE is EMP_ID and FK is DISTRICT_ID.
Primary key for DISTRICT is DISTRICT_ID and FK is SUPERINTENDENT_ID.
Primary key for TOTAL_PAB is PAB_ID and FK is EMP_ID.
The query seems legit, but you should give us some more informations for a better answer.
Generally, it's not important if a field is key or not: the important thing is that ONLY fields in "ON" part of the join statement will be used for matching rows.

Resources