oracle (+) operator in where with >(more) or <(less) - sql

I've read about it and know how it works in this cases
select a.id
from a, b
where a.id = b.id(+)
but what about this?
select a.id
from a, b
where a.id = b.id2(+) and a.id > b.id(+)
it is not the same as
select a.id
from a
left outer join b
on a.id = b.id2
where a.id > b.id
how would I change it?
I need to rewrite it to hive but hive does not support
on a.id = b.id and a.id > b.id;

Although not exactly the same (there are some edge cases), this might do what you want:
select a.id
from a left outer join
b
on a.id = b.id2
where (a.id > b.id or b.id2 is null);
However, your expression is only picking up the id from a and it is using a left join. Hence, this is probably good enough:
select a.id
from a ;
Admittedly, it doesn't return the duplicates generated by the match to the b table, but duplicates are not usually desirable.

Related

Right join vs left join, which table is left vs right?

Given
select *
from a
left join b
on a.id = b.id
is table a left and table b right?
Would that be equivalent to
Select *
from a
right join b
on b.id = a.id
because I switched left and right while flipping the ON clause? Or is a still left because it came first and b is right because it's the thing we're joining?
Thank you.
No. "left" and "right" refer to the ordering of the tables in the FROM clause. So these are equivalent:
select *
from a left join
b
on a.id = b.id
select *
from b right join
a
on a.id = b.id
These two on clauses do exactly the same thing:
on a.id = b.id
on b.id = a.id
They do not affect the results at all.

Simplifying code with nested JOINs in WHERE clause

I'm writing an SQL statement in PostgreSQL where I'm JOINing data from different tables that are each connected by foreign keys on their ids. Table b has a field a_id which relates to the id of table a and so on.
My problem is that I want to reuse a value from the joined table in a WHERE clause without having to do all the JOINs again, like this:
SELECT *
FROM a
INNER JOIN b ON b.a_id = a.id
INNER JOIN c ON c.b_id = b.id
WHERE a.id = 3
AND a.x =
(SELECT c.y
FROM a
INNER JOIN b ON b.a_id = a.id
INNER JOIN c ON c.b_id = b.id
WHERE a.id = 3
AND c.id = 5)
I bet there's a simpler solution for this snippet that I'm just not realising. I'll be glad if anybody can help me out.
I don't have a silver bullet answer which simplifies your query, but CTEs certainly could make it a bit easier on the eyes:
WITH cte AS (
SELECT *
FROM a
INNER JOIN b ON b.a_id = a.id
INNER JOIN c ON c.b_id = b.id
WHERE a.id = 3
)
SELECT *
FROM cte
WHERE x IN (SELECT y FROM cte WHERE c_id = 5);
My aliases or column names may be off, and you may need to tidy up the CTE a bit before it would actually work for you.
You can use window functions for this:
SELECT . . .
FROM (SELECT a.*, b.*, c.*, -- should list the columns explicitly
MAX(c.y) FILTER (WHERE c.id = 5) OVER () as y_5
FROM a INNER JOIN
b
ON b.a_id = a.id INNER JOIN
c
ON c.b_id = b.id
WHERE a.id = 3
) abc
WHERE abc.x = abc.y_5;
I hope the below-mentioned query will help you.
SELECT *
FROM a
INNER JOIN b ON b.a_id = a.id
INNER JOIN c ON c.b_id = b.id
WHERE a.id = 3 and c.id =5 and a.x = c.y

How to use case when in sql query

query="SELECT a.id, b.id
FROM tab_a a, tab_b b
WHERE a.ref = b.ref
AND a.amount = -b.amount
AND NOT a.tot AND NOT b.tot
AND a.a_id = %(a_id)s AND b.a_id = %(a_id)s
{p_id_condition}
ORDER BY a.date desc"
i am trying
first try to match the ref, but if no pair found, try to match the amount
Would something like this work:
SELECT
a.id,
b.id
FROM tab_a a
INNER JOIN tab_b b
ON a.ref = b.ref OR
a.amount = -b.amount
WHERE
NOT a.tot AND
NOT b.tot AND
a.a_id = %(a_id)s AND
b.a_id = %(a_id)s
{p_id_condition}
ORDER BY a.date DESC
I rewrote your query using explicit join syntax, which isolated and revealed the two join conditions you mentioned in your question. Then I changed the and to an or, which would seem to be what you want.

Right join with a where clause

I found a query like this in code:
SELECT *
FROM a
RIGHT JOIN b ON a.id = b.id
WHERE a.id = b.id
Is it basically the same as an inner join on a.id = b.id?
Yes, this is basically the same as an inner join.
The where clause will fail when there are no matches, because the value a.id will be NULL.

oracle sql full join with table a not in

I have to tables (tbla and tblb) with each one col (id):
select * from tbla;
ID
---
1
3
5#A
select * from tblb;
ID
---
2
3
Now I need a full join:
select a.id, b.id
from tbla a
full outer join tblb b on b.id = a.id;
ID ID1
--------
1
3 3
5#A
2
... but without entries containing a #-sign in tbla.id
select a.id, b.id
from tbla a
full outer join tblb b on b.id = a.id
where a.id not like '%#%';
ID ID1
--------
1
3 3
why is the entry with id 2 from tblb missing?
Because when you do a full outer join, columns on either side can end up with a NULL value.
Explicitly check for NULL:
select a.id, b.id
from tbla a
full outer join tblb b on b.id = a.id
where a.id not like '%#%' or a.id is null;
(Originally, I had suggested moving the logic to the on clause. Alas, the full outer join keeps records in both tables, even when no records match the condition. So, moving the condition to the on clause doesn't fix anything.)
When you do outer joins, you have to do your filtering in the from clause. If you do it in the where clause your join effectively becomes an inner join.
So change this:
full outer join tblb b on b.id = a.id
where a.id not like '%#%'
to this
full outer join tblb b on b.id = a.id
and a.id not like '%#%'
You are doing a full join, but by specifying a.id in the where clause, you filter your result set afterwards.
To achieve what you want, you can either move the clause into the join condition:
select a.id, b.id
from tbla a
full outer join tblb b
on b.id = a.id
and a.id not like '%#%';
Or you can use nvl:
select a.id, b.id
from tbla a
full outer join tblb b on b.id = a.id
where nvl(a.id, 'n/a') not like '%#%';
Or explicitly allow NULL values for a.id:
select a.id, b.id
from tbla a
full outer join tblb b on b.id = a.id
where (a.id is null or a.id not like '%#%');