Home » SQL & PL/SQL » SQL & PL/SQL » Oracle Join on Tables (11g)
Oracle Join on Tables [message #595463] |
Wed, 11 September 2013 06:18 |
|
developer12
Messages: 88 Registered: July 2013
|
Member |
|
|
CREATE TABLE MTCH_TBL
(
S_PAID VARCHAR2(100),
S_SEC NUMBER,
H_PAID VARCHAR2(100),
H_SEC NUMBER
);
CREATE TABLE HIST_TBL
(
SEC_ALIAS NUMBER,
INSTANCE NUMBER,
EFF_DATE DATE
);
Here, HIST_TBL is empty.
However, I have a record in MTCH_TBL as:
Insert into MTCH_TBL
(S_PAID, S_SEC, H_PAID, H_SEC)
Values
('Q00', 3944, 'Q00', 526);
My requirement is to match the records in MTCH_TBL and HIST_TBL on the basis of joining S_SEC(MTCH_TBL) with SEC_ALIAS(HIST_TBL)
and INSTANCE(HIST_TBL) as 100 and choosing the record with max EFF_DATE from HIST_TBL.
I have come up with a query as:
select a.h_sec, a.s_paid, a.h_paid
FROM MTCH_TBL a,
HIST_TBL b
where a.S_SEC=b.sec_alias(+)
and b.instance(+)=100
and b.EFF_DATE =
(SELECT MAX (b2.EFF_DATE)
FROM HIST_TBL b2
WHERE b.sec_alias = b2.sec_alias
AND b.instance = b2.instance);
Results obtained:
H_SEC = ''
S_PAID = ''
H_PAID = Q00
Can anyone help me do the join using the EFF_DATE field also and get the expected results.
My results are appearing as BLANK. However I need to produce the results as stated below:
Required results:
Now, i need the results as:
H_SEC = 526
S_PAID = Q00
H_PAID = Q00
|
|
|
|
|
Re: Oracle Join on Tables [message #595476 is a reply to message #595463] |
Wed, 11 September 2013 06:39 |
|
Michel Cadot
Messages: 68645 Registered: March 2007 Location: Nanterre, France, http://...
|
Senior Member Account Moderator |
|
|
I have not the same result than you:
SQL> CREATE TABLE MTCH_TBL
2 (
3 S_PAID VARCHAR2(100),
4 S_SEC NUMBER,
5 H_PAID VARCHAR2(100),
6 H_SEC NUMBER
7 );
Table created.
SQL>
SQL> CREATE TABLE HIST_TBL
2 (
3 SEC_ALIAS NUMBER,
4 INSTANCE NUMBER,
5 EFF_DATE DATE
6 );
Table created.
SQL> Insert into MTCH_TBL
2 (S_PAID, S_SEC, H_PAID, H_SEC)
3 Values
4 ('Q00', 3944, 'Q00', 526);
1 row created.
SQL> commit;
Commit complete.
SQL> select a.h_sec, a.s_paid, a.h_paid
2 FROM MTCH_TBL a,
3 HIST_TBL b
4 where a.S_SEC=b.sec_alias(+)
5 and b.instance(+)=100
6 and b.EFF_DATE =
7 (SELECT MAX (b2.EFF_DATE)
8 FROM HIST_TBL b2
9 WHERE b.sec_alias = b2.sec_alias
10 AND b.instance = b2.instance);
no rows selected
Note that as all columns in the result are from A and not from B, you can eliminate B from the query.
Note that an Oracle outer join on a constant is converted to an INNER join. When you have to do things like this you must use the ANSI syntax.
Regards
Michel
|
|
|
|
|
Re: Oracle Join on Tables [message #595486 is a reply to message #595477] |
Wed, 11 September 2013 06:56 |
|
Maaher
Messages: 7065 Registered: December 2001
|
Senior Member |
|
|
I suggest you use an inner select where you join HIST_TBL with an group query of HIST_TBL.
Je m'excuse, Michel, mais je ne sais pas comment l'expliquer sans inclure le code.
It would be something like this (you can figure out the rest, I guess)
Select a.h_sec
, a.s_paid
, a.h_paid
, b.<other_fields>
...
...
From mtch_tbl a
, ( Select h.sec_alias
, h.instance
, h.other_col
From hist_tbl h
, ( Select sec_alias
, instance
, max(eff_date) eff_date
From hist_tbl
Group By sec_alias, instance
) h2
Where h.sec_alias = h2.sec_alias
And h.instance = h2.instance
And h.eff_date = h2.eff_date
) b
Where ...
...
MHE
[Updated on: Wed, 11 September 2013 06:57] Report message to a moderator
|
|
|
Re: Oracle Join on Tables [message #595496 is a reply to message #595476] |
Wed, 11 September 2013 07:20 |
cookiemonster
Messages: 13920 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
Michel Cadot wrote on Wed, 11 September 2013 12:39Note that an Oracle outer join on a constant is converted to an INNER join. When you have to do things like this you must use the ANSI syntax.
Outer join on a constant is not converted to inner or this wouldn't work:
SQL> select a.h_sec, a.s_paid, a.h_paid
FROM MTCH_TBL a,
HIST_TBL b
where a.S_SEC=b.sec_alias(+)
and b.instance(+)=100;
2 3 4 5
H_SEC
----------
S_PAID
--------------------------------------------------------------------------------
H_PAID
--------------------------------------------------------------------------------
526
Q00
Q00
SQL>
It's the lack of a (+) next to b.EFF_DATE that makes it an inner join. Adding it gives:
SQL> select a.h_sec, a.s_paid, a.h_paid, B.AME
2 FROM MTCH_TBL a,
3 HIST_TBL b
4 where a.S_SEC=b.sec_alias(+)
5 and b.instance(+)=100
6 and b.EFF_DATE(+) =
7 (SELECT MAX (b2.EFF_DATE)
8 FROM HIST_TBL b2
9 WHERE b.sec_alias = b2.sec_alias
10 AND b.instance = b2.instance);
AND b.instance = b2.instance)
*
ERROR at line 10:
ORA-01799: a column may not be outer-joined to a subquery
So yes the ansi syntax is required.
|
|
|
|
|
Re: Oracle Join on Tables [message #595503 is a reply to message #595499] |
Wed, 11 September 2013 07:34 |
cookiemonster
Messages: 13920 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
I thought ansi got you round that, apparently not. Here's one way:
select a.h_sec, a.s_paid, a.h_paid, b.ame
FROM MTCH_TBL a
LEFT OUTER JOIN
HIST_TBL b
ON (a.S_SEC=b.sec_alias)
and (b.instance=100)
WHERE (b.EFF_DATE =
(SELECT MAX (b2.EFF_DATE)
FROM HIST_TBL b2
WHERE b.sec_alias = b2.sec_alias
AND b.instance = b2.instance))
OR b.eff_date IS NULL;
|
|
|
Re: Oracle Join on Tables [message #595504 is a reply to message #595502] |
Wed, 11 September 2013 07:36 |
cookiemonster
Messages: 13920 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
developer12 wrote on Wed, 11 September 2013 13:32Think I have got it:
select a.h_sec, a.s_paid, a.h_paid, B.AME
FROM MTCH_TBL a
LEFT OUTER JOIN HIST_TBL b ON (a.S_SEC=b.sec_alias)
LEFT OUTER JOIN HIST_TBL b ON (b.instance=100)
LEFT OUTER JOIN HIST_TBL ON (b.EFF_DATE =
(SELECT MAX (b2.EFF_DATE)
FROM HIST_TBL b2
WHERE b.sec_alias = b2.sec_alias
AND b.instance = b2.instance));
Definitely not. That's effectively doing an or on all the join conditions.
|
|
|
|
Re: Oracle Join on Tables [message #595525 is a reply to message #595496] |
Wed, 11 September 2013 09:03 |
|
Michel Cadot
Messages: 68645 Registered: March 2007 Location: Nanterre, France, http://...
|
Senior Member Account Moderator |
|
|
cookiemonster wrote on Wed, 11 September 2013 14:20
Outer join on a constant is not converted to inner or this wouldn't work:
...
Yes, my bad, it is converted if there are ONLY outer conditions on constants which is not the case here.
Regards
Michel
[Updated on: Wed, 11 September 2013 09:03] Report message to a moderator
|
|
|
|
Re: Oracle Join on Tables [message #596030 is a reply to message #596029] |
Tue, 17 September 2013 08:58 |
Lalit Kumar B
Messages: 3174 Registered: May 2013 Location: World Wide on the Web
|
Senior Member |
|
|
b2 refers to HIST_TBL to select the MAX(EFF_DATE). But, you said HIST_TBL is empty. So, to filter the eff_date > '01-Jan-2005' will end up as no rows returned if you apply the filter in this statement. You can do that with HIST_TBL in the inner query which refers to HIST_TBL as "b" not "b2" since it has a left outer join which would still return the record from MTCH_TBL.
But what's the point of the filter you want to apply? You are already fetching the max date for which you want the output. This is a bit ambiguous.
[Updated on: Tue, 17 September 2013 09:12] Report message to a moderator
|
|
|
|
Re: Oracle Join on Tables [message #596032 is a reply to message #596031] |
Tue, 17 September 2013 09:14 |
Lalit Kumar B
Messages: 3174 Registered: May 2013 Location: World Wide on the Web
|
Senior Member |
|
|
developer12 wrote on Tue, 17 September 2013 19:42Yes correct the scenario was so earlier.
But now, if I have 2 records with diff dates in the hist_tbl and then need to filter that out!
You should tell that before. How would anybody know the requirement at your side has changed.
Anyway, please provide the insert statements for HIST_TBL. And the current logic of the query is to select a record from MTCH_TBL for a maximum date in HIST_TBL. That will still work. Did you try that, what was the output. Post the SQL*Plus session.
[Updated on: Tue, 17 September 2013 09:20] Report message to a moderator
|
|
|
Re: Oracle Join on Tables [message #596033 is a reply to message #596032] |
Tue, 17 September 2013 09:33 |
|
developer12
Messages: 88 Registered: July 2013
|
Member |
|
|
Insert into HIST_TBL
(SEC_ALIAS, INSTANCE, EFF_DATE, AME)
Values
(322, 100, TO_DATE('01/20/2006 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 'USD');
Insert into HIST_TBL
(SEC_ALIAS, INSTANCE, EFF_DATE, AME)
Values
(606, 100, TO_DATE('01/20/2007 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 'USD');
|
|
|
Re: Oracle Join on Tables [message #596034 is a reply to message #596033] |
Tue, 17 September 2013 10:02 |
Lalit Kumar B
Messages: 3174 Registered: May 2013 Location: World Wide on the Web
|
Senior Member |
|
|
1. Since both the records have date > '01-Jan-2005'. So, the same code will still work. MAX will return you a single value. In this case, it will be '01/20/2007'.
2. Now, even if you have all the records with date < '01-Jan-2005' in HIST_TBL, the current left outer join condition will give you the same output.
Basically, you want to filter the records from HIST_TBL based on EFF_DATE, which is pointless in this case with LEFT OUTER JOIN with MTCH_TBL. If you do not want records if EFF_DT in HIST_TBL < '01-Jan-2005', then get rid of the outer join.
|
|
|
Re: Oracle Join on Tables [message #596143 is a reply to message #596034] |
Wed, 18 September 2013 05:13 |
|
developer12
Messages: 88 Registered: July 2013
|
Member |
|
|
I could basically come up with this code for the requirement I had:
SELECT c.H_SEC,
c.S_PAID,
c.H_PAID,
table_c.EFF_DATE
FROM MTCH_TBL c
LEFT OUTER JOIN
(SELECT b.SEC_ALIAS,
b.EFF_DATE,
b.INSTANCE
FROM HIST_TBL b
WHERE b.EFF_DATE =
(SELECT MAX (b2.EFF_DATE)
FROM HIST_TBL b2
WHERE b.SEC_ALIAS = b2.SEC_ALIAS
AND b.INSTANCE =
b2.INSTANCE
AND b2.EFF_DATE >= '01-Jan-2007')
OR b.EFF_DATE IS NULL) table_c
ON table_c.SEC_ALIAS=c.H_SEC
AND table_c.INSTANCE = 100;
insert into MTCH_TBL
values('6100',50695,'17-Sep-2013','16-Sep-2013','6100',1124);
Insert into HIST_TBL
(SEC_ALIAS, INSTANCE, EFF_DATE, AME)
Values
(1124, 100, TO_DATE('01/20/2006 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 'USD');
Insert into HIST_TBL
(SEC_ALIAS, INSTANCE, EFF_DATE, AME)
Values
(1124, 100, TO_DATE('01/20/2005 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 'USD');
Can anyone help me optimize the query and formulate a cost-effective code?
|
|
|
Re: Oracle Join on Tables [message #596145 is a reply to message #596143] |
Wed, 18 September 2013 05:20 |
Lalit Kumar B
Messages: 3174 Registered: May 2013 Location: World Wide on the Web
|
Senior Member |
|
|
developer12 wrote on Wed, 18 September 2013 15:43Can anyone help me optimize the query and formulate a cost-effective code?
What is the issue with the current code? Any bottlenecks you find in the execution plan?
|
|
|
|
|
Re: Oracle Join on Tables [message #596148 is a reply to message #596147] |
Wed, 18 September 2013 05:29 |
|
developer12
Messages: 88 Registered: July 2013
|
Member |
|
|
Here it is:
Plan
SELECT STATEMENT CHOOSECost: 3,005 Bytes: 5,874,426 Cardinality: 43,839
9 HASH JOIN OUTER Cost: 3,005 Bytes: 5,874,426 Cardinality: 43,839
1 TABLE ACCESS FULL TABLE (TEMP) MTCH_TBL Cost: 2 Bytes: 117 Cardinality: 1
8 VIEW APP_DEVELOPMENT. Cost: 3,002 Bytes: 745,263 Cardinality: 43,839
7 FILTER
3 TABLE ACCESS BY GLOBAL INDEX ROWID TABLE HIST_TBL Cost: 2,999 Bytes: 745,263 Cardinality: 43,839 Partition #: 5 Partition access computed by row location
2 INDEX RANGE SCAN INDEX HIST_IDX1 Cost: 266 Cardinality: 43,839
6 SORT AGGREGATE Bytes: 17 Cardinality: 1
5 FIRST ROW Cost: 3 Bytes: 17 Cardinality: 1
4 INDEX RANGE SCAN (MIN/MAX) INDEX (UNIQUE) SECURITYDBO.PK_HIST Cost: 3 Bytes: 17 Cardinality: 1
|
|
|
|
|
Re: Oracle Join on Tables [message #596159 is a reply to message #596158] |
Wed, 18 September 2013 07:38 |
Lalit Kumar B
Messages: 3174 Registered: May 2013 Location: World Wide on the Web
|
Senior Member |
|
|
Per your question here in OraFAQ and in OTN (https://forums.oracle.com/thread/2583138), you are expected to provide the necessary information for performance tuning related issues. since it is not a defined process to tune a query, it is a manual task and mind it, sometimes a heck of a task. You will get as many inputs as possible, given that you provide as much info as possible.
|
|
|
Re: Oracle Join on Tables [message #596161 is a reply to message #596148] |
Wed, 18 September 2013 07:47 |
Lalit Kumar B
Messages: 3174 Registered: May 2013 Location: World Wide on the Web
|
Senior Member |
|
|
For a start, the following is a bad way, and mostly the chances are that it will suppress the index usage.
AND b2.EFF_DATE >= '01-Jan-2007'
You must use TO_DATE to explicitly convert it to date -
AND b2.EFF_DATE >= TO_DATE('01-Jan-2007', 'DD-Mon-YYYY')
|
|
|
Re: Oracle Join on Tables [message #596162 is a reply to message #596161] |
Wed, 18 September 2013 07:56 |
cookiemonster
Messages: 13920 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
Lalit Kumar B wrote on Wed, 18 September 2013 13:47For a start, the following is a bad way, and mostly the chances are that it will suppress the index usage.
AND b2.EFF_DATE >= '01-Jan-2007'
In this case oracle should implicitly convert the string to a date, so there should be no issues with indexes, but bugs will be encountered if the nls_date_format is changed, so yes, to_Date with a format mask should be used.
|
|
|
Re: Oracle Join on Tables [message #596163 is a reply to message #596162] |
Wed, 18 September 2013 08:05 |
cookiemonster
Messages: 13920 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
Can eff_date actually be null?
The only reason I put a null check on it was because of the outer join, but that doen't apply to your revised code.
|
|
|
Re: Oracle Join on Tables [message #596164 is a reply to message #596163] |
Wed, 18 September 2013 08:16 |
cookiemonster
Messages: 13920 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
Can we check the current query actually matches the requirements?
The current query basically states:
Get me every row in MTCH_TBL
For each row in MTCH_TBL optionally get the max(eff_date) from HIST_TBL where HIST_TBL.SEC_ALIAS = MTCH_TBL.H_SEC
and hist_tbl.instance = 100 and hist_tbl.eff_Date > 01-Jan-2007
Is that correct?
Do you need to select any other columns from hist_tbl?
|
|
|
|
|
Re: Oracle Join on Tables [message #596168 is a reply to message #596167] |
Wed, 18 September 2013 08:40 |
cookiemonster
Messages: 13920 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
Then self joining hist_tbl is a waste of time:
SELECT c.H_SEC,
c.S_PAID,
c.H_PAID,
MAX(h.EFF_DATE)
FROM MTCH_TBL c
LEFT OUTER JOIN HIST_TBL h
ON h.SEC_ALIAS=c.H_SEC
AND h.INSTANCE = 100
AND h.EFF_DATE >= to_date('01-Jan-2007', 'DD-Mon-YYYY')
GROUP BY c.H_SEC,
c.S_PAID,
c.H_PAID;
|
|
|
|
|
|
Re: Oracle Join on Tables [message #596172 is a reply to message #596171] |
Wed, 18 September 2013 09:17 |
cookiemonster
Messages: 13920 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
Most people, on reading my previous post, would automatically, and correctly, assume the answer is - you can't.
There may be ways of rewriting the slow query so that it runs faster, but they will not involve making it look like the last select I posted.
|
|
|
|
Goto Forum:
Current Time: Fri Apr 26 10:12:33 CDT 2024
|