This question already has answers here:
Oracle syntax left joins three or more tables
(2 answers)
Closed 7 years ago.
I have some tables in Oracle.
Table_1 contains :
id|name
1|boy
2|roy
Table_2 contains :
id|value
1|90
2|100
Table_3 contains :
id|class
1|A
2|B
I want to join all three tables.
Query_1 :
SELECT A.ID,A.NAME,B.VALUE,C.CLASS
FROM
TABLE_1 A, TABLE_2 B, TABLE_3 C
WHERE
A.ID=B.ID(+) AND
B.ID=C.ID(+)
OR
Query_2 :
SELECT A.ID,A.NAME,B.VALUE,C.CLASS
FROM
TABLE_1 A, TABLE_2 B, TABLE_3 C
WHERE
A.ID=B.ID(+) AND
A.ID=C.ID(+)
Which one is true?
When you need an Outer Join:
Your query will include two or more tables where there may not exist a match for every record. Examples will explain best. If you have two tables: "Parent", and "Work". If you want to ask the question: What contacts do we have within our parent list within local employers an inner join works fine:
select w.employer, w.phone, w.address,p.name, p.phone
from work w, parent p
where w.person_id = p.person_id
If the question is where do our parents work -- well some may be unemployed and have no match in the "work" table -- now you need an outer join. in Oracle SQL:
select p.name, p.phone, w.employer, w.phone, w.address,
from work w, parent p
where p.person_id = w.person_id(+)
The (+) always goes on the side where we need to "synthetically" add a missing id.
Related
I have 2 tables.
This is tableA
(invoice,D/O, cost..) and
Table B
(D/O, GRN, Qty)
Now how to use query to show table A include GRN,Qty
See
You need a LEFT OUTER JOIN to retrieve all the records from table A with matched records from table B.
Guessing at the join criteria because your question doesn't say what they are:
select a.*
, b.grn
, b.grn_line
, b.qty_grn
from a
left outer join b
on a.do = b.do
and a.do_line = b.do_line
and a.invoice_line = b.grn_line
my current problem is in 11g, but I am also interested in how this might be solved smarter in later versions.
I want to join two tables. Table A has 10 million rows, Table B is huge and has a billion of records across about a thousand partitions. One partition has around 10 million records. I am not joining on the partition key. For most rows of Table A, one or more rows in Table B will be found.
Example:
select * from table_a a
inner join table_b b on a.ref = b.ref
The above will return about 50 million rows, whereas the results come from about 30 partitions of table b. I am assuming a hash join is the correct join here, hashing table a and FTSing/index-scanning table b.
So, 970 partitions were scanned for no reason. And, I have a third query that could tell oracle which 30 partitions to check for the join.
Example of third query:
select partition_id from table_c
This query gives exactly the 30 partitions for the query above.
To my question:
In PL/SQL one can solve this by
select the 30 partition_ids into a variable (be it just a select listagg(partition_id,',') ... into v_partitions from table_c
Execute my query like so:
execute immediate 'select * from table_a a
inner join table_b b on a.ref = b.ref
where b.partition_id in ('||v_partitions||')' into ...
Let's say this completes in 10 minutes.
Now, how can I do this in the same amount of time with pure SQL?
Just simply writing
select * from table_a a
inner join table_b b on a.ref = b.ref
where b.partition_id in (select partition_id from table_c)
does not do the trick it seems, or I might be aiming at the wrong plan.
The plan I think I want is
hash join
table a
nested loop
table c
partition pruning here
table b
But, this does not come back in 10 minutes.
So, how to do this in SQL and what execution plan to aim at? One variation I have not tried yet that might be the solution is
nested loop
table c
hash join
table a
partition pruning here (pushed predicate from the join to c)
table b
Another feeling I have is that the solution might lie in joining table a to table c (not sure on what though) and then joining this result to table b.
I am not asking you to type everything out for me. Just a general concept of how to do this (getting partition restriction from a query) in SQL - what plan should I aim at?
thank you very much! Peter
I'm not an expert at this, but I think Oracle generally does the joins first, then applies the where conditions. So you might get the plan you want by moving the partition pruning up into a join condition:
select * from table_a a
inner join table_b b on a.ref = b.ref
and b.partition_id in (select partition_id from table_c);
I've also seen people try to do this sort of thing with an inline view:
select * from table_a a
inner join (select * from table_b
where partition_id in (select partition_id from table_c)) b
on a.ref = b.ref;
thank you all for your discussions with me on this one. In my case this was solved (not by me) by adding a join-path between table_c and table_a and by overloading the join conditions as below. In my case this was possible by adding column partition_id to table_a:
select * from
table_c c
JOIN table_a a ON (a.partition_id = c.partition_id)
JOIN table_b b ON (b.partition_id = c.partition_id and b.partition_id = a.partition_id and b.ref = a.ref)
And this is the plan you want:
leading(c,b,a) use_nl(c,b) swap_join_inputs(a) use_hash(a)
So you get:
hash join
table a
nested loop
table c
partition list iterator
table b
This question already has answers here:
Update statement with inner join on Oracle
(15 answers)
Closed 8 years ago.
I am new to Oracle SQL and need some help with the writing the following query. Any guidance would be greatly appreciated. I am not sure I am going down the correct path with this or not.
I have two tables t1 and t2. t1 contains four fields f1...f4. t2 contains the same four fields. I need to update t1.f1 and t1.f4 with the values from t2.f1 and t2.f4, respectively, where t1.f2 = t2.f2 and t1.f3 = t2.f3. If there is a row that does not match these conditions, The row should not be updated.
Am I on the right path or completely lost?
UPDATE t1
SET (t1.f1=t2.f1,
t1.f4=t2.f4)
FROM t1
INNER JOIN (SELECT t2.f1, t2.f4 FROM t2)
ON t1.f2=t2.f2 AND t1.f3=t2.f3
WHERE EXISTS (SELECT t2.f1, t2.f4
FROM t2
WHERE t1.f2=t2.f2 AND t1.f3=t2.f3);
Might be easier if you use a MERGE statement. Something like:
MERGE INTO t1
USING
(SELECT f1,f2,f3,f4 FROM t2) t2
ON
(t1.f2=t2.f2
AND t1.f3 = t2.f3)
WHEN MATCHED THEN
update set t1.f1 = t2.f1,
t1.f4 = t2.f4;
If you are using Oracle version 9i or above 'MERGE' is the best way to do it.
Or you can rewrite your above query like this
UPDATE table1 t1
SET (t1.f1,t1.f2) = (
select t2.f1,t2.f4 from table2 t2
where t1.f2 = t2.f2 and t1.f3 = t2.f3)
WHERE EXISTS (SELECT 1
FROM table2 t2
WHERE t1.f2=t2.f2 AND t1.f3=t2.f3);
I have two tables A and B that both have a column id. I wish to obtain ids from A that are not present in B. The obvious way is:
SELECT id FROM A WHERE id NOT IN (SELECT id FROM B)
Unfortunately, Hive doesn't support in, exists or subqueries. Is there a way to achieve the above using joins?
I thought of the following
SELECT A.id FROM A,B WHERE A.id<>B.id
But it seems like this will return the entirety of A, since there always exists an id in B that is not equal to any id in A.
You can do the same with a LEFT OUTER JOIN in Hive:
SELECT A.id
FROM A
LEFT OUTER JOIN B
ON (B.id = A.id)
WHERE B.id IS null
Hive seems to support IN, NOT IN, EXIST and NOT EXISTS from 0.13.
select count(*)
from flight a
where not exists(select b.tailnum from plane b where b.tailnum = a.tailnum);
The subqueries in EXIST and NOT EXISTS should have correlated predicates (like b.tailnum = a.tailnum in above sample)
For more, refer Hive Wiki > Subqueries in the WHERE Clause
Should you ever want to do an IN as so:
SELECT id FROM A WHERE id IN (SELECT id FROM B)
Hive has this covered with a LEFT SEMI JOIN:
SELECT a.key, a.val
FROM a LEFT SEMI JOIN b on (a.key = b.key)
if you can using spark sql you can use left anti join.
ex: SELECT A.id FROM A left anti join B on a.id=b.id
I have 2 views:
View VIEW5_SUMA that contains SUM of prices for all items (cars), it is one row and it's constant I need to "join"
View VIEW4_SUMA_AUTA that contains SUM of all incomes for specific item (car)
SQL> SELECT * FROM VIEW5_SUMA ;
CELKOVA_TRZBA
-------------
5806
SQL> SELECT * FROM VIEW4_SUMA_AUTA ;
TRZBA_AUTA ID_AUTO
---------- ----------
360 1
... ...
I need to create another view, that will contain percents of income for every item. The problem is, I dont know how to "JOIN" that one row from VIEW5_SUMA (constant of total income) to my select so I can calculate with it.
This is what I got so far but it returns error:
CREATE VIEW VIEW6 AS
SELECT
t1.typ,
t1.specifikacia_typu,
t1.SPZ,
t2.trzba_auta/(t3.celkova_trzba/100) AS percenta
FROM AUTA t1, VIEW5_SUMA t3
JOIN VIEW4_SUMA_AUTA t2 ON t1.id_auto = t2.id_auto
;
The problem you see is due to the fact that the JOIN binds tighter than the comma so what you wrote is equivalent to
FROM AUTA t1, (VIEW5_SUMA t3 JOIN VIEW4_SUMA_AUTA t2 ON t1.id_auto = t2.id_auto)
Seeing how there is no table t1 inside the parenthesis this won't work.
That means all you have to do is to change the order so that the binding works as you want it:
CREATE VIEW VIEW6 AS
SELECT
t1.typ,
t1.specifikacia_typu,
t1.SPZ,
t2.trzba_auta/(t3.celkova_trzba/100) AS percenta
FROM AUTA t1 JOIN VIEW4_SUMA_AUTA t2 ON t1.id_auto = t2.id_auto,
VIEW5_SUMA t3
;
Alternatively you can use a CROSS JOIN which is the same thing as a comma because it results in a cartesian product or changes into an inner join if there is a where clause.
FROM AUTA t1 CROSS JOIN VIEW5_SUMA t3 JOIN VIEW4_SUMA_AUTA t2 ON (...)
FROM AUTA t1 JOIN VIEW4_SUMA_AUTA t2 ON (...) CROSS JOIN VIEW5_SUMA t3
The CROSS JOIN is a JOIN so you have the expected parenthesis ((CROSS JOIN) JOIN )
Oh I found one way just after posting my question. If I dont use JOIN at all but rather specify multiple tables in FROM and then join tables with WHERE it works.
SELECT
t1.typ,
t1.specifikacia_typu,
t1.SPZ,
t2.trzba_auta/(t3.celkova_trzba/100) AS percenta
FROM AUTA t1, VIEW4_SUMA_AUTA t2, VIEW5_SUMA t3
WHERE
t1.id_auto = t2.id_auto
;
But I'm still curious if there's way to do this with JOIN.
'Returns error' is not helpful in diagnosing the problem. I'd guess it says that t1.id_auto is an invalid identifier.
Mixing the old join syntax (multiple comma-separated tables in the from clause and the join condition in the where clause) and the 'new' syntax (join and on) is confusing and doesn't always work; I'd recommend always using the 'new' syntax anyway.
You can do this with join, but you have to only use that form. Since there is no join condition between t1 and t3, you need a cross join. This produces the cartesian product of the two tables, which isn't often what you want, but in this case since one the of the tables has a single row it seems appropriate.
CREATE VIEW VIEW6 AS
SELECT
t1.typ,
t1.specifikacia_typu,
t1.SPZ,
t2.trzba_auta/(t3.celkova_trzba/100) AS percenta
FROM AUTA t1
CROSS JOIN VIEW5_SUMA t3
JOIN VIEW4_SUMA_AUTA t2 ON t1.id_auto = t2.id_auto
Building views on top of views isn't always a good idea and can cause performance issues.