Oracle where clause outer join - oracle

I am having trouble understanding how to do an outer join using the where clause for a particular query. I can accomplish the join using the JOIN keyword. The query I am trying to accomplish is:
-- display a list of all books in the books table. if a book has been ordered by a customer also list the corresponding order number and state the customer is from
here is the table structure
desc customers
Name Null Type
--------- -------- ------------
CUSTOMER# NOT NULL NUMBER(4)
LASTNAME NOT NULL VARCHAR2(10)
FIRSTNAME NOT NULL VARCHAR2(10)
ADDRESS VARCHAR2(20)
CITY VARCHAR2(12)
STATE VARCHAR2(2)
ZIP VARCHAR2(5)
REFERRED NUMBER(4)
REGION CHAR(2)
EMAIL VARCHAR2(30)
desc orders
Name Null Type
---------- -------- ------------
ORDER# NOT NULL NUMBER(4)
CUSTOMER# NUMBER(4)
ORDERDATE NOT NULL DATE
SHIPDATE DATE
SHIPSTREET VARCHAR2(18)
SHIPCITY VARCHAR2(15)
SHIPSTATE VARCHAR2(2)
SHIPZIP VARCHAR2(5)
SHIPCOST NUMBER(4,2)
desc orderitems
Name Null Type
-------- -------- ------------
ORDER# NOT NULL NUMBER(4)
ITEM# NOT NULL NUMBER(2)
ISBN VARCHAR2(10)
QUANTITY NOT NULL NUMBER(3)
PAIDEACH NOT NULL NUMBER(5,2)
desc books
Name Null Type
-------- -------- ------------
ISBN NOT NULL VARCHAR2(10)
TITLE VARCHAR2(30)
PUBDATE DATE
PUBID NUMBER(2)
COST NUMBER(5,2)
RETAIL NUMBER(5,2)
DISCOUNT NUMBER(4,2)
CATEGORY VARCHAR2(12)
using join I can get it to display what I believe is the correct results with the following:
SELECT b.title, c.state, order#
FROM customers c JOIN orders o USING (customer#)
JOIN orderitems oi USING (order#)
RIGHT OUTER JOIN books b USING (isbn);
TITLE STATE ORDER#
------------------------------ ----- ----------
HOW TO GET FASTER PIZZA
THE WOK WAY TO COOK
REVENGE OF MICKEY MI 1012
REVENGE OF MICKEY GA 1019
REVENGE OF MICKEY WA 1009
REVENGE OF MICKEY TX 1014
BODYBUILD IN 10 MINUTES A DAY FL 1003
HANDCRANKED COMPUTERS MI 1012
SHORTEST POEMS GA 1005
PAINLESS CHILD-REARING GA 1001
PAINLESS CHILD-REARING NJ 1004
PAINLESS CHILD-REARING FL 1016
PAINLESS CHILD-REARING MI 1012
PAINLESS CHILD-REARING GA 1011
COOKING WITH MUSHROOMS WY 1020
COOKING WITH MUSHROOMS ID 1008
COOKING WITH MUSHROOMS FL 1003
COOKING WITH MUSHROOMS WA 1000
COOKING WITH MUSHROOMS WA 1009
COOKING WITH MUSHROOMS FL 1018
COOKING WITH MUSHROOMS NJ 1015
HOLY GRAIL OF ORACLE TX 1007
BUILDING A CAR WITH TOOTHPICKS
BIG BEAR AND LITTLE DOVE FL 1017
BIG BEAR AND LITTLE DOVE TX 1007
BIG BEAR AND LITTLE DOVE MI 1012
DATABASE IMPLEMENTATION IL 1002
DATABASE IMPLEMENTATION TX 1007
DATABASE IMPLEMENTATION FL 1003
DATABASE IMPLEMENTATION WY 1013
DATABASE IMPLEMENTATION FL 1018
DATABASE IMPLEMENTATION NJ 1010
HOW TO MANAGE THE MANAGER GA 1001
E-BUSINESS THE EASY WAY TX 1007
E-BUSINESS THE EASY WAY FL 1006
35 rows selected
this is what I have tried for my where clause join:
-- using where clause
SELECT b.title, c.state, oi.order#
FROM customers c, orders o, orderitems oi, books b
WHERE c.customer# = o.customer#
AND o.order# = oi.order#
AND oi.isbn(+) = b.isbn;
but when I do this query I get the following
TITLE STATE ORDER#
------------------------------ ----- ----------
BODYBUILD IN 10 MINUTES A DAY FL 1003
REVENGE OF MICKEY GA 1019
REVENGE OF MICKEY TX 1014
REVENGE OF MICKEY MI 1012
REVENGE OF MICKEY WA 1009
DATABASE IMPLEMENTATION FL 1018
DATABASE IMPLEMENTATION WY 1013
DATABASE IMPLEMENTATION NJ 1010
DATABASE IMPLEMENTATION TX 1007
DATABASE IMPLEMENTATION FL 1003
DATABASE IMPLEMENTATION IL 1002
COOKING WITH MUSHROOMS WY 1020
COOKING WITH MUSHROOMS FL 1018
COOKING WITH MUSHROOMS NJ 1015
COOKING WITH MUSHROOMS WA 1009
COOKING WITH MUSHROOMS ID 1008
COOKING WITH MUSHROOMS FL 1003
COOKING WITH MUSHROOMS WA 1000
HOLY GRAIL OF ORACLE TX 1007
HANDCRANKED COMPUTERS MI 1012
E-BUSINESS THE EASY WAY TX 1007
E-BUSINESS THE EASY WAY FL 1006
PAINLESS CHILD-REARING FL 1016
PAINLESS CHILD-REARING MI 1012
PAINLESS CHILD-REARING GA 1011
PAINLESS CHILD-REARING NJ 1004
PAINLESS CHILD-REARING GA 1001
BIG BEAR AND LITTLE DOVE FL 1017
BIG BEAR AND LITTLE DOVE MI 1012
BIG BEAR AND LITTLE DOVE TX 1007
HOW TO MANAGE THE MANAGER GA 1001
SHORTEST POEMS GA 1005
32 rows selected
Here is a link to the sql that will build the structure if needed https://www.dropbox.com/s/7tpbpz1hbufj3qn/JLDB_Build_8.sql
I am having a hard time figuring out what I am doing wrong/different with the where clause join. Any help or direction is appreciated.
Thanks.

when using joins I recommend to do explicit left/right joins. For example..
Select A.*, B.*, C.*
from TableA A
left outer join TableB B
on A.field1 = B.fkfield1
and A.field2 0 B.fkfield2
...
left outer join TableC C
on A.field1 = C.fkfield1
and A.field2 0 C.fkfield2
...
In this case, the Table A records will be matched with the ones on Table B. If thereĀ“s no match on table B, then the columns from table B will be null. The second joins works loke the first one, this case will also show null if there is no matching value from field1 (on table A) in the Table C, fkfield1.
On the other hand, if you need to match all the records of the second table insteade of the first you need to do a "inner join". Just replace "left outer join" with "inner join" in the example above.
Thanks!
#leo

Try this:
SELECT b.title, o.state, o.order#
FROM books b
, (select o.order#, oi.isbn, o.customer#, c.state
from orders o, orderitems oi, customers c
where o.order# = oi.order#
and c.customer# = o.customer#
) o
WHERE
AND o.isbn(+) = b.isbn;

I found this after lots more digging
this is from http://docs.oracle.com/cd/B19306_01/server.102/b14200/queries006.htm
If A and B are joined by multiple join conditions, then you must use
the (+) operator in all of these conditions. If you do not, then
Oracle Database will return only the rows resulting from a simple
join, but without a warning or error to advise you that you do not
have the results of an outer join.
The (+) operator does not produce an outer join if you specify one
table in the outer query and the other table in an inner query.
I was able to get it working with the following:
SELECT b.title, c.state, o.order#
FROM customers c, orders o, orderitems oi, books b
WHERE c.customer#(+) = o.customer#
AND o.order#(+) = oi.order#
AND oi.isbn(+) = b.isbn;

Related

Self table comparison

I Have a table emp which has
ename sal
Smith 1000
Mark 2000
Jack 500
The output should be(person earning lower salary on the left)
Jack Smith
Jack Mark
Smith Mark
Please help
Seems like a cross join with a filter.
select h1.ename as first, h2.ename as second
from have as h1
cross join have as h2
where h1.sal>h2.sal

Count Different Values in Oracle Using Outer Joins

My question is about left outer join with counter. I have two tables.
employee:
empid empname
----- -------
101 Tom
102 Jerry
103 Jack
104 Tim
allocation:
generator analyzer tester
--------- -------- ------
101 102 103
103 102 101
102 101 104
I need following result
empid empname generator analyzer tester
------ ------- --------- -------- -------
101 Tom 1 1 1
102 Jerry 1 2 0
103 Jack 1 0 1
104 Tim 0 0 1
I need to count the values of each task. Tom has generated 1, analyzed 1
and tested 1. Like that i need to count the values. Is this possible in
SQL. If this is possible please help me to get output.
I am getting the result. but it is not expected. I have used outer joins to solve the problem,
select
e.empid,
e.empname,
count(a1.generator),
count(a2.analyzer),
count(a3.tester)
from employee e
left join allocation a1
on e.empid=a1.author
left join allocation a2
on e.empid=a2.reviewer
left join allocation a3
on e.empid=a3.tester
group by
e.empid,
e.empname;
You can achieve it with this:
Select empid,sum(generaor),sum(analyzer),sum(tester)
from
(
Select empid,count(a.generaor) generaor,0 analyzer,0 tester
from employee
JOIN Allocation a on empid=a.generaor group by empid,a.generaor
UNION
Select empid,0 generaor,count(b.analyzer)analyzer,0 tester
from employee
JOIN Allocation b on empid=b.analyzer group by empid,b.analyzer
UNION
Select empid,0 generaor,0 analyzer,count(c.tester) tester
from employee
JOIN Allocation c on empid=c.tester group by empid,c.tester
) stag
group by empid
Try this
SELECT empid, empname, sum(generator), sum(analyzer), sum(tester) FROM
(SELECT e.empid, e.empname, count(a1.generator) generator, 0 analyzer, 0 tester
FROM Employee e
JOIN Allocation a1 ON a1.generator = e.empid
GROUP BY e.empname
UNION
SELECT e.empid, e.empname, 0 generator, count(a2.analyzer) analyzer, 0 tester
FROM Employee e
JOIN Allocation a2 ON a2.analyzer = e.empid
GROUP BY e.empname
UNION
SELECT e.empid, e.empname, 0 generator, 0 analyzer, count(a3.tester) tester
FROM Employee e
JOIN Allocation a3 ON a3.tester = e.empid
GROUP BY e.empname) tmp
GROUP BY empname
ORDER BY empid

hierarchy level in relationship table in oracle

I have a table employee which has hierarchy data of manager and employee.
Sample data.
empId ManId
101 100
102 100
1010 101
1011 101
10101 1010
I need to find the level but it is not giving me correct output. I need an output like
level Emp ID Man Id
1 101 100
1 102 100
2 1010 101
2 1011 101
3 10101 1010
Irrespective of the input as Emp ID or Man ID, the output should be constant. I am only getting the output when I am using manager id as 100 but it doesnt work when i pass value as 10101
select distinct
level,
manager_id,
employee_id
from employees
START WITH manager_id = 100
connect by manager_id= prior employee_id
order by level
START WITH clause is used to specify a root row for the hierarchy which is employee id with 101 value
Kindly use the below
select distinct
level,
manager_id,
employee_id
from employees
where level<=3
START WITH employee_id = 101
connect by manager_id= prior employee_id
order siblings by employee_id
Update1:-:-You can remove START WITH if root row is not specific
select distinct
level,
manager_id,
employee_id
from employees
where level<=3
connect by manager_id= prior employee_id
order siblings by employee_id
Check this link for more information
Hierarchical Queries

Hive: Sum over a specified group (HiveQL)

I have a table:
key product_code cost
1 UK 20
1 US 10
1 EU 5
2 UK 3
2 EU 6
I would like to find the sum of all products for each group of "key" and append to each row. For example for key = 1, find the sum of costs of all products (20+10+5=35) and then append result to all rows which correspond to the key = 1. So end result:
key product_code cost total_costs
1 UK 20 35
1 US 10 35
1 EU 5 35
2 UK 3 9
2 EU 6 9
I would prefer to do this without using a sub-join as this would be inefficient. My best idea would be to use the over function in conjunction with the sum function but I cant get it to work. My best try:
SELECT key, product_code, sum(costs) over(PARTITION BY key)
FROM test
GROUP BY key, product_code;
Iv had a look at the docs but there so cryptic I have no idea how to work out how to do it. Im using Hive v0.12.0, HDP v2.0.6, HortonWorks Hadoop distribution.
Similar to #VB_ answer, use the BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING statement.
The HiveQL query is therefore:
SELECT key, product_code,
SUM(costs) OVER (PARTITION BY key ORDER BY key ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM test;
You could use BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW to achieve that without a self join.
Code as below:
SELECT a, SUM(b) OVER (PARTITION BY c ORDER BY d ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
FROM T;
The analytics function sum gives cumulative sums. For example, if you did:
select key, product_code, cost, sum(cost) over (partition by key) as total_costs from test
then you would get:
key product_code cost total_costs
1 UK 20 20
1 US 10 30
1 EU 5 35
2 UK 3 3
2 EU 6 9
which, it seems, is not what you want.
Instead, you should use the aggregation function sum, combined with a self join to accomplish this:
select test.key, test.product_code, test.cost, agg.total_cost
from (
select key, sum(cost) as total_cost
from test
group by key
) agg
join test
on agg.key = test.key;
This query gives me perfect result
select key, product_code, cost, sum(cost) over (partition by key) as total_costs from zone;
similar answer (if we use oracle emp table):
select deptno, ename, sal, sum(sal) over(partition by deptno) from emp;
output will be like below:
deptno ename sal sum_window_0
10 MILLER 1300 8750
10 KING 5000 8750
10 CLARK 2450 8750
20 SCOTT 3000 10875
20 FORD 3000 10875
20 ADAMS 1100 10875
20 JONES 2975 10875
20 SMITH 800 10875
30 BLAKE 2850 9400
30 MARTIN 1250 9400
30 ALLEN 1600 9400
30 WARD 1250 9400
30 TURNER 1500 9400
30 JAMES 950 9400
The table above looked like
key product_code cost
1 UK 20
1 US 10
1 EU 5
2 UK 3
2 EU 6
The user wanted a tabel with the total costs like the following
key product_code cost total_costs
1 UK 20 35
1 US 10 35
1 EU 5 35
2 UK 3 9
2 EU 6 9
Therefor we used the following query
SELECT key, product_code,
SUM(costs) OVER (PARTITION BY key ORDER BY key ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM test;
So far so good.
I want a column more, counting the occurences of each country
key product_code cost total_costs occurences
1 UK 20 35 2
1 US 10 35 1
1 EU 5 35 2
2 UK 3 9 2
2 EU 6 9 2
Therefor I used the following query
SELECT key, product_code,
SUM(costs) OVER (PARTITION BY key ORDER BY key ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as total_costs
COUNT(product code) OVER (PARTITION BY key ORDER BY key ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as occurences
FROM test;
Sadly this is not working. I get an cryptic error. To exclude an error in my query I want to ask if I did something wrong.
Thanks

How to convert semicolon separated column into a row in Oracle?

Source Table: EMP_LOCATION
NAME LOCATION
-------------------------------
SMITH NY;CA;IL;GA
JAMES MO;AZ;RI
FORD NJ
SCOTT TX;VA;WA;NH
MARTIN MD;CT
Required Output:
NAME LOCATION
-------------------
FORD NJ
JAMES AZ
JAMES MO
JAMES RI
MARTIN CT
MARTIN MD
SCOTT NH
SCOTT TX
SCOTT VA
SCOTT WA
SMITH CA
SMITH GA
SMITH IL
SMITH NY
Some people will ask you to show some code, but when I needed this I spent a lot of time creating a function then I realize that I could do it with a connect by. So what you need is this:
SELECT name, REGEXP_SUBSTR (location, '[^;]+', 1, LEVEL) AS location
FROM emp_location
CONNECT BY
LEVEL <= LENGTH(REGEXP_REPLACE (location, '[^;]*')) + 1
GROUP BY name, REGEXP_SUBSTR (location, '[^;]+', 1, LEVEL)
ORDER BY name

Resources