Join Table with oracle sql - oracle

I am newbie for Oracle SQL. I wish to join 2 tables.
In TABLE 1 two tables had been join with the below presentation
Here is the sql script for TABLE 1:
select a.ID,
a.CLASSIFICATION_CODE,
a. CATEGORY_CODE
from a, b
where locality = 'xxx'
and a.DIV = b.DIV
and a.TYPE = b.TYPE
and a.DIST = b.DIST
and a.BS = b.BS
and a.LOT = b.LOT;
TABLE 2
Here is the sql script for TABLE 2:
select CODE_TYPE,CODE_1,CODE_DESC from PUBCODE01
where PUBCODE01.code_type IN ('LCL','LCA');
TABLE 3 (the table for final result after join 3 tables)
I need help on how could I combined the two sql script in order to produce the TABLE 3 presentation.

You may need to join twice the same table, based on the code_ty; for example:
SQL> with query1(id, classification_code, category_code) as(
2 select 123, 1, 3 from dual union all
3 select 456, 2, 4 from dual union all
4 select 789, 1, 3 from dual
5 ),
6 query2(code_type, code_1, code_desc) as (
7 select 'LCL', 1, 'TOMATOES' from dual union all
8 select 'LCL', 2, 'DURIAN' from dual union all
9 select 'LCA', 3, 'VEGETABLE' from dual union all
10 select 'LCA', 4, 'FRUITS' from dual
11 )
12 select id, LCL.code_desc, LCA.code_desc
13 from query1
14 inner join query2 LCL
15 on(LCL.code_1 = query1.classification_code)
16 inner join query2 LCA
17 on(LCA.code_1 = query1.category_code);
ID CODE_DESC CODE_DESC
---------- --------- ---------
123 TOMATOES VEGETABLE
789 TOMATOES VEGETABLE
456 DURIAN FRUITS
or even the following, depending on what your data can be:
select id, LCL.code_desc, LCA.code_desc
from query1
inner join query2 LCL
on(LCL.code_1 = query1.classification_code
and LCL.code_type = 'LCL')
inner join query2 LCA
on(LCA.code_1 = query1.category_code
and LCA.code_type = 'LCA')
As an aside, you should better use ANSI join; your query should be:
select a.ID,
a.CLASSIFICATION_CODE,
a. CATEGORY_CODE
from a
inner join b
on(
a.DIV = b.DIV
and a.TYPE = b.TYPE
and a.DIST = b.DIST
and a.BS = b.BS
and a.LOT = b.LOT
)
where locality = 'xxx'

Tomatoes are a fruit, please research your produce before posting.

Related

Multiply with Previous Value from One colum in Oracle SQL

I have the following result, which is easily calculated in Excel, but how to do it in Oracle, the result is the following, based on a previous select and comes from one column,
Result from select Expected result
1.62590
0.60989 0.991620151
0.83859 0.831562742
the result is based on 1.62590 * 0.60989 = 0.991620151,
1.62590 * 0.60989 * 0.83859 = 0.831562742
You can use:
SELECT id,
result,
EXP(SUM(LN(result)) OVER (ORDER BY id)) AS expected
FROM table_name;
Note: Use any other column instead of id to give the appropriate ordering or, if your rows are already ordered, use the ROWNUM pseudo-column instad of id.
Which, for the sample data:
CREATE TABLE table_name (id, Result) AS
SELECT 1, 1.62590 FROM DUAL UNION ALL
SELECT 2, 0.60989 FROM DUAL UNION ALL
SELECT 3, 0.83859 FROM DUAL;
Outputs:
ID
RESULT
EXPECTED
1
1.6259
1.62590000000000000000000000000000000001
2
.60989
.9916201510000000000000000000000000000026
3
.83859
.8315627424270900000000000000000000000085
fiddle
One option is to use a recursive CTE; it, though, expects that sample data can be sorted, somehow, so I added the ID column which starts with 1, while other values are incremented by 1:
Sample data:
SQL> with
2 test (id, col) as
3 (select 1, 1.62590 from dual union all
4 select 2, 0.60989 from dual union all
5 select 3, 0.83859 from dual
6 ),
Query begins here:
7 product (id, col, prod) as
8 (select id, col, col
9 from test
10 where id = 1
11 union all
12 select t.id, t.col, t.col * p.prod
13 from test t join product p on p.id + 1 = t.id
14 )
15 select id,
16 round(prod, 10) result
17 from product;
ID RESULT
---------- ----------
1 1,6259
2 ,991620151
3 ,831562742
SQL>
You can use a MODEL clause:
SELECT *
FROM (SELECT ROW_NUMBER() OVER (ORDER BY id) AS rn, result FROM table_name)
MODEL
DIMENSION BY (rn)
MEASURES ( result, 0 AS expected)
RULES (
expected[rn] = result[cv()] * COALESCE(expected[cv()-1], 1)
)
order by rn;
Which, for the sample data:
CREATE TABLE table_name (id, Result) AS
SELECT 1, 1.62590 FROM DUAL UNION ALL
SELECT 2, 0.60989 FROM DUAL UNION ALL
SELECT 3, 0.83859 FROM DUAL;
Outputs:
RN
RESULT
EXPECTED
1
1.6259
1.6259
2
.60989
.991620151
3
.83859
.83156274242709
fiddle

I need 2 count columns in the same query in ORACLE

I'm trying to get the unique number of invoices a company has received and sent out using 2 count() functions. In invoices table there are two columns that are references to the same company id (one is id of a company that is sending an invoice and the other one is id of a company that is receiving an invoice)
This is the code I tried using:
SELECT K.ID,K.NAME,K.CITY, COUNT(*) AS NUM_OF_INVOICES_SENT, COUNT(*) AS NUM_OF_INVOICES_RECEIVED
FROM COMPANY K LEFT JOIN INVOICE F ON F.COMP_SNEDING = K.ID
GROUP BY K.NAME,K.ID,K.CITY
This is for a school project so I am in no means well versed in sql/oracle
actual data invoices:
actual data company:
desired outcome with given actual data:
Here's one option; it doesn't use count, but sum with case expression.
Sample data:
SQL> with
2 invoice (id, amount, comp_sending, comp_receiving) as
3 (select 1, 2000 , 1, 2 from dual union all
4 select 2, 28250, 3, 2 from dual union all
5 select 3, 8700 , 4, 1 from dual union all
6 select 4, 20200, 5, 3 from dual union all
7 select 5, 21500, 3, 4 from dual
8 ),
9 company (id, name, city, state) as
10 (select 1, 'Microsoft', 'Redmond' , 'Washington' from dual union all
11 select 2, 'Ubisoft' , 'Paris' , 'France' from dual union all
12 select 4, 'Starbucks', 'Seattle' , 'Washington' from dual union all
13 select 5, 'Apple' , 'Cupertino', 'California' from dual union all
14 select 3, 'Nvidia' , 'Cupertino', 'California' from dual
15 )
Query begins here:
16 select c.id, c.name,
17 sum(case when c.id = i.comp_sending then 1 else 0 end) cnt_sent,
18 sum(case when c.id = i.comp_receiving then 1 else 0 end) cnt_received
19 from company c left join invoice i on c.id in (i.comp_sending, i.comp_receiving)
20 group by c.id, c.name
21 order by c.id;
ID NAME CNT_SENT CNT_RECEIVED
---------- --------- ---------- ------------
1 Microsoft 1 1
2 Ubisoft 0 2
3 Nvidia 2 1
4 Starbucks 1 1
5 Apple 1 0
SQL>
You can use COUNT if you replace the 0 in the CASE expressions with NULL. So #Littlefoot's query becomes
select c.id, c.name,
COUNT(case when c.id = i.comp_sending then 1 else NULL end) cnt_sent,
COUNT(case when c.id = i.comp_receiving then 1 else NULL end) cnt_received
from company c left join invoice i on c.id in (i.comp_sending, i.comp_receiving)
group by c.id, c.name
order by c.id;
This works because COUNT counts only those rows which have a non-NULL value in the expression which is being counted.
db<>fiddle here

Count(*) in Group By - Returns 1, instead of '0'

I am using the below oracle query to get the count of rows.
SELECT T.ID,T.NAME,COUNT(*) AS NO_OF_STUDENTS FROM STUDENT S RIGHT JOIN
TEACHER T ON S.TEACHER_ID = T.ID
GROUP BY T.ID,T.NAME ORDER BY T.ID
Actual Result Should be:
TEACHER 1 - 10 STUDENTS
TEACHER 2 - 5 STUDENTS
TEACHER 3 - 0 STUDENT
The Result what i am getting is:
TEACHER 1 - 10 STUDENTS
TEACHER 2 - 5 STUDENTS
TEACHER 3 - 1 STUDENT
Since TEACHER 3 is not having any student, the result should be 0 Student. But i am getting the result as 1 Student.
You need to count a specific column (not use *, which includes nulls) in the table being outer joined to - since that is the one that might not have matching data. So:
SELECT T.ID, T.NAME, COUNT(S.ID) AS NO_OF_STUDENTS
FROM STUDENT S
RIGHT JOIN TEACHER T ON S.TEACHER_ID = T.ID
GROUP BY T.ID, T.NAME
ORDER BY T.ID
The only difference is COUNT(S.ID) instead of COUNT(*).
Simple demo with made-up data provided via CTEs:
with teacher (id, name) as (
select 1, 'Teacher 1' from dual
union all select 2, 'Teacher 2' from dual
union all select 3, 'Teacher 3' from dual
),
student (id, teacher_id) as (
select level, 1 from dual connect by level <= 10
union all
select level + 10, 2 from dual connect by level <= 5
)
SELECT T.ID, T.NAME, COUNT(S.ID) AS NO_OF_STUDENTS
FROM STUDENT S
RIGHT JOIN TEACHER T ON S.TEACHER_ID = T.ID
GROUP BY T.ID, T.NAME
ORDER BY T.ID;
ID NAME NO_OF_STUDENTS
---------- --------- --------------
1 Teacher 1 10
2 Teacher 2 5
3 Teacher 3 0
You could also do this as a left join, which I find more intuitive:
SELECT T.ID, T.NAME, COUNT(S.ID) AS NO_OF_STUDENTS
FROM TEACHER T
LEFT JOIN STUDENT S ON S.TEACHER_ID = T.ID
GROUP BY T.ID, T.NAME
ORDER BY T.ID
which gets the same result.

Subquery Inside Mega Query

I have searched, but can find no example that fits what I need. Perhaps I am lost in the many joins of my query...
I am returning data from three Oracle 11g tables - ATE_TESTS, ATE_DATA, and TM_CONDITION_DYNAMIC. The query has other tables to join these. In fact, there are no less than 7 Joins.
ATE_DATA may have multiple records on the Many side of a join, but I want only the last-written row. ATE_DATA has an incremented Primary Key which I would like to use in the Aggregate Function MAX(DATA_PK) within a subquery. I think it should be in the WHERE clause of the main query, but I do not know how to implement this and there may be a better way.
Perhaps I might be educated?
My query is:
SELECT ate_serial, data_data, dyn_value
FROM ate_tests
LEFT JOIN ate_test_procedure
ON ate_tests.ate_pk = ate_test_procedure.proc_ate_test_fk
LEFT JOIN ate_test_data
ON ate_test_procedure.proc_pk = ate_test_data.data_ate_test_procedure_fk
LEFT JOIN tm_test_procedure
ON ate_test_procedure.proc_test_procedure = tm_test_procedure.proc_pk
LEFT JOIN tm_test_specification
ON ate_test_data.data_specification = tm_test_specification.spec_pk
LEFT JOIN tm_test_condition_dynamic
ON tm_test_specification.spec_condition_set_fk = tm_test_condition_dynamic.dyn_condition_set_fk
LEFT JOIN tm_test_sequences
ON ate_tests.ate_sequence_fk = tm_test_sequences.seq_pk
LEFT JOIN lu_tm_products_model
ON tm_test_sequences.seq_model = lu_tm_products_model.lumod_pk
WHERE upper(spec_name) = 'POWER'
AND lumod_model = 'AMP'
AND dyn_value = '136'
AND ate_yield = 1
AND upper(proc_procedure_name) = 'FINAL TEST'
AND proc_report = 1
AND proc_status = 1
ORDER BY ate_serial, dyn_value
... but I want only the last-written row.
It's typical top-n query. Let's say table a contains info about vegetables, table b their historical prices in different shops and s info about these shops. You are interested only in last price,
which you can find using the function row_number() (or max() ... keep dense rank last...).
with a as (select 1 vid, 'Tomato' name from dual union all
select 2 vid, 'Potato' name from dual union all
select 3 vid, 'Garlic' name from dual),
b as (select 1 pid, 1 vid, 1 sid, 11.5 price from dual union all
select 2 pid, 3 vid, 1 sid, 31.8 price from dual union all
select 3 pid, 1 vid, 1 sid, 13.2 price from dual union all
select 4 pid, 1 vid, 2 sid, 12.7 price from dual ),
s as (select 1 sid, 'Best Vegetables' name from dual union all
select 2 sid, 'Organic Products' name from dual)
select a.vid, a.name, s.name as shop, p.price as last_price
from a
left join (select vid, sid, price
from (select vid, sid, price,
row_number() over (partition by vid order by pid desc) rn
from b)
where rn = 1) p
on p.vid = a.vid
left join s on s.sid = p.sid
order by a.vid
Output:
VID Name Shop Price
--- -------- ------------------ -------
1 Tomato Organic Products 12.7
2 Potato
3 Garlic Best Vegetables 31.8

Oracle join not working

I am trying get all IFSC codes and details (bank unique code) from my bank master which starts with the first 4 characters of entered IFSC code. I have the bank master table which includes IFSC code(4 chars), corresponding bank details.
The main part of the query is given below.
AND D.IFSC_CODE=UPPER(substr(B.BANK_CODE,1,4)) (+) ORDER BY....
When I execute this query, I am getting an error message "ORA-00936: missing expression".
What I am expecting from the query is:
return the details if the bank exists in bank master corresponding to the entered IFSC code
else only entered IFSC should display
When I rewrite the query like
AND D.IFSC_CODE(+) =UPPER(substr(B.BANK_CODE,1,4)) ORDER BY....
There is no error but the result was not what I expected.
How can I resolve this?
In a complex outer join expression you would put the (+) operator on all relevant columns, as in:
AND D.IFSC_CODE=UPPER(substr(B.BANK_CODE (+),1,4))
For example:
SQL> WITH table_a AS (
2 SELECT '0001' ID FROM dual
3 UNION ALL SELECT '0002' FROM dual
4 UNION ALL SELECT '0003' FROM dual
5 ), table_b AS (
6 SELECT '0001a' ID FROM dual
7 UNION ALL SELECT '0002b' FROM dual
8 )
9 SELECT a.id, b.id
10 FROM table_a a, table_b b
11 WHERE a.id = substr(b.id (+), 1, 4);
ID ID
---- -----
0001 0001a
0002 0002b
0003
This form of outer join is specific to Oracle and arguably more difficult to read than SQL ANSI outer join. Additionaly, some specific features are disabled with this old method (full outer join, outer join to more than one table). In SQL ansi join form, the query would look like:
SQL> WITH table_a AS (
2 SELECT '0001' ID FROM dual
3 UNION ALL SELECT '0002' FROM dual
4 UNION ALL SELECT '0003' FROM dual
5 ), table_b AS (
6 SELECT '0001a' ID FROM dual
7 UNION ALL SELECT '0002b' FROM dual
8 )
9 SELECT a.id, b.id
10 FROM table_a a
11 LEFT OUTER JOIN table_b b ON a.id = substr(b.id, 1, 4);
ID ID
---- -----
0001 0001a
0002 0002b
0003

Resources