left outer join on nullable field with between in join condition (Oracle) - oracle

I have two tables as: table1 with fields c1 and dt(nullable); table2 with fields start_dt, end_dt and wk_id. Now I need to perform left outer join between the table1 and table2 to take wk_id such that dt falls between start_dt and end_dt. I applied following condition but some wk_id which shouldn't be NULL are pulled NULL and some rows get repeated.
where nvl(t1.dt,'x') between nvl(t2.start_dt(+), 'x') and nvl(t2.end_dt(+), 'x');
What is wrong with the condition?

select *
from table1 t1
left join table2 t2
on t1.dt between t2.start_dt and t2.end_dt
I recommend you try the new ANSI join syntax.
Also, are you just using 'x' as an example? Or are the dt columns really stored as strings?

It seems you are missing the part "table1 left outer join table2 on table1.some_field = table2.some_field"
Something like this:
select t1.c1, t1.dt, t2.start_dt, t2.end_dt, t2.wk_id
from table1 t1 left outer join table2 t2
on t1.some_field1 = t2.some_field1
where nvl(t1.dt,'x')
between nvl(t2.start_dt, 'x') and
nvl(t2.end_dt, 'x')

Related

getting error- ORA-00905: missing keyword

Select * from table1 t1 left outer join table2 t2 on t1.id=t2.id and
case
when t1.id in (select t2.id from table2)
then t1.valid_to_ts > sysdate and t2.valid_to_ts>sysdate
else
t1.valid_to_ts>sysdate.
getting error-
ORA-00905: missing keyword
You can use UNIONs to implement the logic of the case:
SELECT *
FROM table1 t1 LEFT JOIN table2 t2 ON t1.id = t2.id
WHERE t2.id IS NULL
AND t1.valid_to_ts > SYSDATE
UNION ALL
SELECT *
FROM table1 t1 LEFT JOIN table2 t2 ON t1.id = t2.id
WHERE t1.id IS NOT NULL
AND t1.valid_to_ts > SYSDATE
AND t2.valid_to_ts > SYSDATE;
As Álvaro González said in a comment, you can't use a case expression as a flow control operator. You can use a case expression in a where or on clause, but only by making it generate a value which you then compare with something else, which can be awkward, so it's usually better not to. You can usually replace the logic you're trying to implement with simple Boolean logic.
In this case you're already joining to table2 so your subquery isn't needed; you can use a where clause to see if a matching record was found - preferably checking for a not-null column other than ID, so this example will only work if valid_to_ts is not nullable:
select * from table1 t1
left outer join table2 t2
on t1.id = t2.id
where t1.valid_to_ts > sysdate
and (t2.valid_to_ts is null or t2.valid_to_ts > sysdate)
If t2.valid_to_ts is nullable then you should use a different not-nullable column instead; unless you want to include values with no valid-to date - but you aren't doing that for t1.valid_to_ts.
If you try to check that in the on clause then you won't filter out IDs which do exist in table2 but with an earlier date.
db<>fiddle, including an on-clause version which gets the wrong result (as far as I can tell from your starting query anyway).
For the demo I've assumed that the _ts columns are dates, since you're comparing with sysdate; if they are actually timestamps (as the suffix might suggest) then you could compare with systimestamp instead.

Oracle join clause where varchar2(4 byte) causing issue

Title was tough to choose my wording.
I have 2 tables I want to join together via a lg_code. Both columns are VARCHAR2(4 byte). I am running into an issue where table1 lg_code = 0003 and table2 lg_code = 3. The three 0's are causing an issue with the join and not returning all the data needed. How would I go about writing the join clause to fix this issue?
Code:
select * from table1 t1 JOIN table2 t2 ON t1.LG_CODE = t2.LG_CODE
I would suggest to convert the value of the columnlg_code to number first then make the join:
SELECT * FROM table1 t1
JOIN table2 t2 ON to_number(t1.LG_CODE) = to_number(t2.LG_CODE)
you can also use ltrim() on them:
SELECT * FROM table1 t1
JOIN table2 t2 ON LTRIM(t1.LG_CODE, '0') = LTRIM(t2.LG_CODE, '0');
but in newer versions of oracle SQL*PLUS it trims automatically.

Fetching other rows of table when performing inner join over multiple fields (oracle query)

select pmt.col1,table2.col1,table2.col3,table3.col1,table3.col1
from table2 inner join (select distinct
col1,col2 from table1) pmt on
table2.col1=pmt.col1 inner join table3 on
table3.col1=table1.col2 where table2.col2 is null;
Is there any way I can select pmt.col3(which is other column of table1) in this very query only.
Thanks very much
Simply select the column in a the sub query. Use for instance max for limiting the result set to one record:
select pmt.col1,
(select max(col3)
from table1 t1
where t1.col1 = pmt.col1
and t1.col2 = pmt.col2) col3,
table2.col1,
table2.col3,
table3.col1,
table3.col1
from table2
inner join (select distinct col1,col2
from table1) pmt
on table2.col1=pmt.col1
inner join table3
on table3.col1=table1.col2
where table2.col2 is null;

Return non-null value from two tables in Oracle

I have two tables, T1 and T2 with same set of columns. I need to issue a query which will return me value of columns from either table whichever is not null. If both columns are null return null as the value of that column.
The columns are c1,c2,c3,cond1.
I issued the following query. The problem is that if one subquery fails the whole query fails. Somebody please help me. Probably there is another simple way.
SELECT NVL(T1.c1, T2.c1) c1,NVL(T1.c2, T2.c2) c2,NVL(T1.c3, T2.c3) c3
FROM (SELECT c1,c2,c3
FROM T1
WHERE cond1 = 'T10') T1
,(SELECT c1,c2,c3
FROM T2
WHERE cond1 = 'T200') T2 ;
You need something like this:
SELECT NVL((SELECT T1.c1
FROM T1
WHERE T1.c2 = 'T10'),
(SELECT T2.c1
FROM T2
WHERE T2.c2 = 'T200')) AS c1
FROM dual
Or you may prefer a full outer join:
SELECT NVL(T1.c1, T2.c1) AS c1
FROM T1 FULL OUTER JOIN T2 ON 1=1
WHERE T1.c2 = 'T10'
AND T2.c2 = 'T200'
Your result is logical. If the first table is null no combination of values will exist in the natural join.
EDIT. After some new requirements we can use a hack to get the row. Lets get all three possibilities, T1, T2 or all nulls and select the first one:
SELECT *
FROM ( (SELECT T1.*
FROM T1
WHERE T1.c2 = 'T10')
UNION ALL
(SELECT T2.*
FROM T2
WHERE T2.c2 = 'T200')
UNION ALL
(SELECT T2.*
FROM dual
LEFT JOIN T1 ON 1 = 0 ) )
WHERE ROWNUM = 1

I want to update T1 using T3 column and by using three table relationships

UPDATE TABLE1 T1 SET T1.CENTERNAME=
(SELECT AC.CENTERNAME
FROM TABLE2 T2 INNER JOIN TABLET3 AN ON T2.CENTERID = T3.LOCATIONID
INNER JOIN TABLE1 T1 ON T3.LOG_ID = T1.LOGID W
HERE TRUNC(T1.ROW_DATE)='25-MAR-2014');
This gives the error 'ORA-01427: single-row subquery returns more than one row'.
The error message
ORA-01427: single-row subquery returns more than one row
means, er, the sub-query returns more than row. That is, this part of your statement ...
(SELECT AC.CENTERNAME
FROM TABLE2 T2 INNER JOIN TABLET3 AN ON T2.CENTERID = T3.LOCATIONID
INNER JOIN TABLE1 T1 ON T3.LOG_ID = T1.LOGID
WHERE TRUNC(T1.ROW_DATE)='25-MAR-2014')
returns more than row. The error occurs because the SET part of the UPDATE depends on the equality operator - SET T1.CENTERNAME= - so it can take only be one value.
Without more details about your data structure it is hard to be certain but I suspect what you really want is something like this
UPDATE TABLE1 T1
SET T1.CENTERNAME= (SELECT T2.CENTERNAME
FROM TABLE2 T2
INNER JOIN TABLE3 T3
ON T2.CENTERID = T3.LOCATIONID
WHERE T3.LOG_ID = T1.LOGID )
WHERE TRUNC(T1.ROW_DATE)='25-MAR-2014'
/
(I've tidied up your redaction to make the aliases consistent.)

Resources