I want to structure a query with no using INNER JOIN. I figured out that an INNER like this:
Select A.Name
from A INNER JOIN B on (A.id1 = B.id1 AND A.id2 = B.id2)
Where B.id = #Id
produce the same as:
select A.Name
from A
where
A.id1 in (select B.id1 from B where B.id = #Id)
and
A.id2 in (select B.id2 from B where B.id = #Id)
Isn't it?
Note that my question is not about if it is better or not, only if it is an equivalent or if there is not an equivalente for that INNER.
Your second query may match id1 and id2 from different B rows, so that query may return rows not expected. You have to keep id1 and id2 together:
Use EXISTS:
select A.Name
from A
where exists (select * from B
where A.id1 = B.id1 AND A.id2 = B.id2
and B.id = #Id)
or "Row and table constructors"
select A.Name
from A
where (A.id1, A.id2) in (select B.id1, B.id2 from B where B.id = #Id)
Related
I have two SQL queries where uses an inner join first to match based on a condition, and the other does not. Ultimately, I would like the difference between the columns created by each query. How can I do this?
I have tried unioning and joining the queries as in some similar posts, but it won't work. I wonder if the issue is around the joins within each query.
Query 1 :
SELECT A.date, COUNT(DISTINCT A.id)
FROM A
INNER JOIN B
ON A.id = B.id AND A.date = B.date
AND B.col1 = 'value1'
LEFT JOIN C on C.key = A.key
WHERE A.col1 = 'value2'
AND C.category = 'cat1'
GROUP BY 1
ORDER BY 1 DESC
Query 2 :
SELECT A.date, COUNT(DISTINCT A.id)
FROM A
LEFT JOIN C on C.key = A.key
WHERE A.col1 = 'value2'
AND C.category = 'cat1'
GROUP BY 1
ORDER BY 1 DESC
Your left join of c is actually turned to an inner join because it's used in a NULL excluding expression in the WHERE clause. So you can directly inner join c and left join b. Then you can use a case in one count() to count only the instances where a row from b was joined. Subtract that value from another count() counting all occurrences to get difference.
SELECT a.date,
count(DISTINCT a.id)
-
count(DISTINCT CASE
WHEN b.id IS NOT NULL THEN
a.id
END)
FROM a
INNER JOIN c
ON c.key = a.key
AND c.category = 'cat1'
LEFT JOIN b
ON a.id = b.id
AND a.date = b.date
AND b.col1 = 'value1'
WHERE a.col1 = 'value2'
GROUP BY 1
ORDER BY 1 DESC;
SELECT A.date, COUNT(DISTINCT A.id)
FROM A
INNER JOIN B
ON A.id = B.id AND A.date = B.date
AND B.col1 = 'value1'
LEFT JOIN C on C.key = A.key
WHERE A.col1 = 'value2'
AND C.category = 'cat1'
GROUP BY 1
ORDER BY 1 DESC
UNION
SELECT A.date, COUNT(DISTINCT A.id)
FROM A
LEFT JOIN C on C.key = A.key
WHERE A.col1 = 'value2'
AND C.category = 'cat1'
GROUP BY 1
ORDER BY 1 DESC
A simple way is to JOIN the two queries, using the date column, which is available in both queries :
SELECT x.date, x.cnt, y.cnt, y.cnt - x.cnt
FROM
(
SELECT A.date, COUNT(DISTINCT A.id) AS cnt
FROM A
INNER JOIN B ON A.id = B.id AND A.date = B.date AND B.col1 = 'value1'
LEFT JOIN C on C.key = A.key
WHERE A.col1 = 'value2' AND C.category = 'cat1'
GROUP BY 1
) AS x
INNER JOIN (
SELECT A.date, COUNT(DISTINCT A.id) AS cnt
FROM A
LEFT JOIN C on C.key = A.key
WHERE A.col1 = 'value2' AND C.category = 'cat1'
GROUP BY 1
) AS y ON x.date = y.date
ORDER BY 1 DESC
You might want to adapt the join type according to your data layout :
LEFT JOIN if all dates are available in the first subquery but may be missing in the second subquery
RIGHT JOIN if the situation is the other way around
FULL OUTER JOIN if you want all available dates from both ends
If you choose any of the above option, you would need to use COALESCE to prevent the substraction to return NULL when one of the terms is NULL.
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.
I've got two queries that return single result.
They look something like this
// query 1
SELECT A.id FROM tableA A
INNER JOIN tableB B
ON B.id = A.id
WHERE b.status = 'ACTIVE'
// query 2
SELECT C.id FROM tableC C
WHERE c.status = 'ACTIVE'
How to combine them and make return the pair of values instead of one value from different queries? I mean to get something like [A.id, C.id]
Currently I have to use two queries in the applications and I want to combine them into one.
I think like this will do
SELECT (SELECT A.id FROM tableA A
INNER JOIN tableB B
ON B.id = A.id
WHERE b.status = 'ACTIVE'
) as 'query1',
(
SELECT C.id FROM tableC C
WHERE c.status = 'ACTIVE'
) as 'query2'
As your question is not clear, so i assume that you either needids from mentioned queries in one row or in different rows, you can use union all/union (provided that datatypes are compatible or implicitly convertible and duplicates or allowed or not) as below.
Combining Result in different rows.
SELECT A.id
FROM tableA A
INNER JOIN tableB B
ON B.id = A.id
WHERE b.status = 'ACTIVE'
union all
SELECT C.id
FROM tableC C
WHERE c.status = 'ACTIVE'
Combining Result in Single Row.
select max(id1), max(id2)
from(
SELECT A.id as id1, NULL as id2
FROM tableA A
INNER JOIN tableB B
ON B.id = A.id
WHERE b.status = 'ACTIVE'
union all
SELECT NULL, C.id
FROM tableC C
WHERE c.status = 'ACTIVE'
) t;
SAMPLE DEMO
You can run following query which work fine for me:
select t1.id as aid ,t2.id as cid
from (
SELECT A.id
FROM tableA A
INNER JOIN tableB B ON B.id = A.id
WHERE b.status = 'ACTIVE'
) t1
full outer join (
SELECT C.id
FROM tableC C
WHERE c.status = 'ACTIVE'
) t2 on t1.id=t2.id
You can join your second query with your first query as follows, so that you will get two (A.id, C.id) values in one query...
SELECT A.ID,C.ID FROM
(SELECT A.ID FROM table_A A INNER JOIN
table_B B ON A.ID=B.ID WHERE B.STATUS='A')A
INNER JOIN table_c C
ON C.ID=A.ID WHERE C.STATUS='A';
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.
I have a query that joins to several tables. Based on the column value of one table, I would like the key value of another table. But, when this key value is joined to another table (with the purpose of identifying different date values for that key), several dates appear. I would like to return the Key Value whose date is most recent when joined to another table. I have a query that works, but it is very redundant, as the sub-query is nearly identical to the main query. I didn't know if there was a technique or better way to achieve this.
Example query:
SELECT distinct TableA.key
FROM TableA a INNER JOIN TableB b
ON a.key = b.Key
INNER JOIN TableC c ON b.Key2 = c.Key2
INNER JOIN TableD d ON b.Key = d.Key
WHERE b.column1 = XYZ
AND c.column1 = 123
and d.date =
(SELECT max(d.date)
FROM TableA a INNER JOIN TableB b
ON a.Key = b.Key
INNER JOIN TableC c ON b.Key2 = c.Key2
INNER JOIN TableD d ON b.Key = d.Key
WHERE b.column1 = XYZ
AND c.column1 = 123
)
Try this. Use Top 1 with ties order by date desc
SELECT distinct TOP 1 with ties TableA.key
FROM TableA a INNER JOIN TableB b
ON a.key = b.Key
INNER JOIN TableC c ON b.Key2 = c.Key2
INNER JOIN TableD d ON b.Key = d.Key
WHERE b.column1 = XYZ
AND c.column1 = 123
order by d.date desc