Oracle join not working - oracle

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

Related

Join Table with oracle sql

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.

Optimise Oracle Join query (multiple joins on the same table)

I have three tables in my Oracle database:
Table 1: Contains employees and phone numbers from Company A:
EmployeeName, WorkPhone, MobilePhone, PersonalPhone,OtherPhone
Adam,1234,1111,0987,NULL
Catherine,2345,5432,NULL,NULL
Tom, 4567,7654,0101,0002
Table 2: Contains employees and phone numbers from Company B:
EmployeeName, WorkPhone, MobilePhone, PersonalPhone, OtherPhone
David,8888,9999,0000,1245
Sam,4321,5432,NULL,NULL
Clara,4567,7654,0101,NULL
Table 3: Contains phone numbers where the phone number could either be recorded in Column 1 or in Column 2 or in both:
PhoneNumber1, PhoneNumber2
1234,NULL
7654,7575
0000,1111
1234,4321
NULL,1234
5432,1234
Now, I would like to join phone numbers in Table 3 to their respective employees as well as to know where that employee works (Company A or B). The challenge is that we have a total of 8 "matching" possibilities for Table 2 and 8 for Table 2 (Each column in Table A/B can join to either column 1 or column2 in Table 3.
The datasets are big. (20M rows in table 1 and about 2M rows in table 2).Let's leave out Table2 for now and concentrate on joining Table1 to Table3 only.
If I do the following, the query is very very slow (and I imagine it would run out of temp table space at some point):
SELECT * FROM Table3 t3
LEFT JOIN Table1 t1
ON (PhoneNumber1 in (WorkPhone, MobilePhone, PersonalPhone, OtherPhone)
OR PhoneNumber2 in (WorkPhone, MobilePhone, PersonalPhone, OtherPhone))
If I do the following, the query runs out of temp table space (and i am not allowed to increase that)
SELECT * FROM Table3
LEFT JOIN Table1 t1_1
PhoneNumber1 = t1_1.WorkPhone
LEFT JOIN Table1 t1_2
PhoneNumber1 = t1_1.MobilePhone
LEFT JOIN Table1 t1_3
PhoneNumber1 = t1_1.PersonalPhone
...etc
How could we optimise this query?
You could unpivot either or both tables so you get a row for each (not-null) phone number, and then do a simple join:
with cte1 as (
select * from (
select 'A' as company, t.* from table1 t
union all
select 'B' as company, t.* from table2 t
)
unpivot (phone for type in (workphone as 'Work', mobilephone as 'Mobile',
personalphone as 'Personal', otherphone as 'Other'))
),
cte2 as (
select distinct phone from table3
unpivot (phone for type in (phonenumber1 as 'Phone1', phonenumber2 as 'Phone2'))
)
select cte1.*
from cte2
join cte1 on cte1.phone = cte2.phone;
C EMPLOYEEN TYPE PHON
- --------- -------- ----
A Adam Work 1234
A Adam Mobile 1111
A Catherine Mobile 5432
A Tom Mobile 7654
B David Personal 0000
B Sam Work 4321
B Sam Mobile 5432
B Clara Mobile 7654
8 rows selected.
The first CTE first unions tables 1 and 2 together, while adding a pseudocolumn indicating which table the data came from; and then unpivots the result so you get one row per phone number per person:
...
select * from cte1;
C EMPLOYEEN TYPE PHON
- --------- -------- ----
A Adam Work 1234
A Adam Mobile 1111
A Adam Personal 0987
A Catherine Work 2345
A Catherine Mobile 5432
...
B Clara Personal 0101
18 rows selected.
You could also unpivot each table first and then union those together, might be worth trying both ways.
The second CTE unpivots table 3 so you get one row for each not-null phone number in either column:
...
select * from cte2;
PHON
----
7654
7575
0000
4321
1234
5432
1111
7 rows selected.
Of course, this is on a tiny amount of dummy data; it might perform even worse on your actual larger tables... And I've made some assumptions about what you want to end up with.
Another approach might be to just convert the table 3 values into a single column which you can do manually instead of explicitly unpivoting, and then unioning together multiple queries against eachof the first two tables:
with cte as (
select phone from (
select phonenumber1 as phone from table3
union
select phonenumber2 as phone from table3
)
where phone is not null
)
select 'A' as customer, employeename, 'Work' as type, workphone as phone
from table1 where workphone in (select phone from cte)
union all
select 'A', employeename, 'Mobile', mobilephone
from table1 where mobilephone in (select phone from cte)
union all
select 'A', employeename, 'Personal', mobilephone
from table1 where personalphone in (select phone from cte)
union all
select 'A', employeename, 'Other', mobilephone
from table1 where otherphone in (select phone from cte)
union all
select 'B', employeename, 'Work', workphone
from table2 where workphone in (select phone from cte)
union all
select 'B', employeename, 'Mobile', mobilephone
from table2 where mobilephone in (select phone from cte)
union all
select 'B', employeename, 'Personal', personalphone
from table2 where personalphone in (select phone from cte)
union all
select 'B', employeename, 'Other', otherphone
from table2 where otherphone in (select phone from cte)
/
C EMPLOYEEN TYPE PHON
- --------- -------- ----
A Adam Work 1234
A Adam Mobile 1111
A Catherine Mobile 5432
A Tom Mobile 7654
B Sam Work 4321
B Sam Mobile 5432
B Clara Mobile 7654
B David Personal 0000
8 rows selected.
Which I personally find harder to read and maintain, but it may perform significantly differently too.

How to breakdown data by month and showing zero for months with no data?

Using information in Table A, how can I produce results in Table B below?
Table A:
CASE_ID DATE_EFF COPAY STATUS
1 11/04/2016 10 A
1 11/20/2016 5 A
1 11/23/2016 5 R
1 12/01/2016 1 A
1 12/10/2016 2 A
1 12/12/2016 10 A
1 12/31/2016 50 R
For the above CASE_ID, we have dates in Nov 2016 and Dec 2016 only, however, I want to produce a breakdown of this CASE_ID for a period of 6 months as below where for each month the copays are summed where applicable as per the DATE_EFF and for the months that are not within the above dates, a zero is entered. Also, only records with copays with a status of 'A' are summed for any month -- so those with status of 'R' are ignored in the summation. For example, based on data in Table A above, the intended results are as follow:
Table B:
CASE_ID MONTH TOTAL_COPAY
1 01/2017 0
1 12/2016 13
1 11/2016 15
1 10/2016 0
1 09/2016 0
1 08/2016 0
I have below as a possible solution[using a with clause], but can this be achieved without the use of the 'with' clause?
Possible Solution:
WITH
XRF AS
( SELECT CASE_ID, COPAY, DATE_EFF
FROM Table_A WHERE STATUS = 'A'
)
SELECT F.CASE_ID, ST, NVL(SUM(F.COPAY),0) TOTAL_COPAY FROM XRF F PARTITION BY (F.CASE_ID)
RIGHT OUTER JOIN (SELECT '12/2016' ST FROM DUAL UNION ALL
SELECT '11/2016' FROM DUAL UNION ALL
SELECT '10/2016' FROM DUAL UNION ALL
SELECT '09/2016' FROM DUAL UNION ALL
SELECT '08/2016' FROM DUAL UNION ALL
SELECT '07/2016' FROM DUAL) STS
ON (TO_CHAR(LAST_DAY((F.DATE_EFF)),'MM/YYYY') = STS.ST)
GROUP BY F.CASE_ID, ST ORDER BY F.CASE_ID, ST DESC
;
UPDATE AND SOLUTION:
Using the above query, I believe I am have answered my own question by implementing it as below -- not sure though if using this method is expensive when you have millions of records of such CASE_IDs. Any thoughts?
SELECT F.CASE_ID, ST, NVL(SUM(F.COPAY),0) TOTAL_COPAY FROM (SELECT CASE_ID, COPAY, DATE_EFF FROM TABLE_A WHERE STATUS = 'A') F PARTITION BY (F.CASE_ID)
RIGHT OUTER JOIN (SELECT '12/2016' ST FROM DUAL UNION ALL
SELECT '11/2016' FROM DUAL UNION ALL
SELECT '10/2016' FROM DUAL UNION ALL
SELECT '09/2016' FROM DUAL UNION ALL
SELECT '08/2016' FROM DUAL UNION ALL
SELECT '07/2016' FROM DUAL) STS
ON (TO_CHAR(LAST_DAY((F.DATE_EFF)),'MM/YYYY') = STS.ST)
GROUP BY F.CASE_ID, ST ORDER BY F.CASE_ID, ST DESC
;

Fetching Lastrow from the table in toad

I have to fetch the first and last row of the table in Toad.
I have used the following query
select * from grade_master where rownum=(select max(rownum) from grade_master)
select * from grade_master where rownum=1
The second query works to fetch the first row. but the first not working. Anyone please help me.
Thanks in advance
Such request makes sense if you specify sort order of the results - there are no such things in database as "first" and "last" rows if sort order is not specified.
SQL> with t as (
2 select 'X' a, 1 b from dual union all
3 select 'C' , 2 from dual union all
4 select 'A' a, 3 b from dual
5 )
6 select a, b, decode(rn, 1, 'First','Last')
7 from (
8 select a, b, row_number() over(order by a) rn,
9 count(*) over() cn
10 from t
11 )
12 where rn in (1, cn)
13 order by rn
14 /
A B DECOD
- ---------- -----
A 3 First
X 1 Last
In oracle the data is not ordered until you specify the order in you sql statement.
So when you do:
select * from grade_master
oracle will give the rows in anyway it want wants.
OTOH if you do
select * from grade_master order by id desc
Then oracle will give the rows back ordered by id descending.
So to get the last row you could do this:
select *
from (select * from grade_master order by id desc)
where rownum = 1
The rownum is determined BEFORE the "order by" clause is assessed, so what this query is doing is ordering the rows descending (the inside query) and then giving this ordered set to the outer query. The outer gets the first row of the set then returns it.

Oracle sql retrive records based on maximum time

i have below data.
table A
id
1
2
3
table B
id name data1 data2 datetime
1 cash 12345.00 12/12/2012 11:10:12
1 quantity 222.12 14/12/2012 11:10:12
1 date 20/12/2012 12/12/2012 11:10:12
1 date 19/12/2012 13/12/2012 11:10:12
1 date 13/12/2012 14/12/2012 11:10:12
1 quantity 330.10 17/12/2012 11:10:12
I want to retrieve data in one row like below:
tableA.id tableB.cash tableB.date tableB.quantity
1 12345.00 13/12/2012 330.10
I want to retrieve based on max(datetime).
The data model appears to be insane-- it makes no sense to join an ORDER_ID to a CUSTOMER_ID. It makes no sense to store dates in a VARCHAR2 column. It makes no sense to have no relationship between a CUSTOMER and an ORDER. It makes no sense to have two rows in the ORDER table with the same ORDER_ID. ORDER is also a reserved word so you cannot use that as a table name. My best guess is that you want something like
select *
from customer c
join (select order_id,
rank() over (partition by order_id
order by to_date( order_time, 'YYYYMMDD HH24:MI:SS' ) desc ) rnk
from order) o on (c.customer_id=o.order_id)
where o.rnk = 1
If that is not what you want, please (as I asked a few times in the comments) post the expected output.
These are the results I get with my query and your sample data (fixing the name of the ORDER table so that it is actually valid)
SQL> ed
Wrote file afiedt.buf
1 with orders as (
2 select 1 order_id, 'iphone' order_name, '20121201 12:20:23' order_time from dual union all
3 select 1, 'iphone', '20121201 12:22:23' from dual union all
4 select 2, 'nokia', '20110101 13:20:20' from dual ),
5 customer as (
6 select 1 customer_id, 'paul' customer_name from dual union all
7 select 2, 'stuart' from dual union all
8 select 3, 'mike' from dual
9 )
10 select *
11 from customer c
12 join (select order_id,
13 rank() over (partition by order_id
14 order by to_date( order_time, 'YYYYMMDD HH24:MI:SS' ) desc ) rnk
15 from orders) o on (c.customer_id=o.order_id)
16* where o.rnk = 1
SQL> /
CUSTOMER_ID CUSTOM ORDER_ID RNK
----------- ------ ---------- ----------
1 paul 1 1
2 stuart 2 1
Try something like
SELECT *
FROM CUSTOMER c
INNER JOIN ORDER o
ON (o.CUSTOMER_ID = c.CUSTOMER_ID)
WHERE TO_DATE(o.ORDER_TIME, 'YYYYMMDD HH24:MI:SS') =
(SELECT MAX(TO_DATE(o.ORDER_TIME, 'YYYYMMDD HH24:MI:SS')) FROM ORDER)
Share and enjoy.

Resources