Exclude using joins without subquery - sql

how to converse following code to get the same results using join (without using subquery)
select a_key from table_a a
inner join table_b b --in my code I've 5 joins like that
on a.a_key=b.a_key
where a_key not in
(select a_key from table_c --and conditions within this brackets also
where var_a beteween table_c.col1 and table_c.col2
or var_b beteween table_c.col1 and table_c.col2
)

The following is essentially the same logic:
select a_key
from table_a a inner join
table_b b
on a.a_key = b.a_key left join
table_c c
on (var_a between table_c.col1 and table_c.col2 or
var_b between table_c.col1 and table_c.col2
) and
a.a_key = c.a_key
where c.a_key is null;
You should prefix your columns with table aliases. The column a_key is ambiguous in your original, as are the column var_a and var_b.
These are slightly different if any matching table_c.a_key values are NULL. In that case, the join version probably behaves more like you would expect.

Related

SQL inner join with conditional selection

I am new in SQL. Lets say I have 2 tables one is table_A and the other one is table_B. And I want to create a view with two of them which is view_1.
table_A:
id
foo
1
d
2
e
null
f
table_B
id
name
1
a
2
b
3
c
and when I use this query :
SELECT DISTINCT table_A.id, table_B.name
FROM table_A
INNER JOIN table_B ON table_B.id = table_A.id
the null value in table_A can't be seen in the view_1 since it is not found in table_B. I want view_1 to show also this null row like :
id
name
1
a
2
b
null
no entry
Should I create a 4. table? I couldn't find a way.
Try this Query:
SELECT DISTINCT a.id,(CASE When b.name IS NULL OR b.name = '' Then 'No Entry' else b.name end) name FROM table_A a
LEFT JOIN table_B b on a.id = b.id
You are looking for an outer join. Thus you keep all table_A rows and join table_B rows where they exist. If no match exists, the table_B columns in the joined row are NULL.
You replace NULLs with a value with COALESCE.
SELECT a.id, COALESCE(b.name, 'no entry') AS name
FROM table_a a
LEFT OUTER JOIN table_b b ON b.id = a.id
ORDER BY a.id NULLS LAST;
You haven't tagged your request with your DBMS. Not all DBMS support the NULLS LAST clause.
Please note that there is no DISTINCT in my query. It is not needed. And every time you think you must use DISTINCT, think twice. SELECT DISTINCT is very seldom needed. Most often it is used, because the query is kind of flawed and causes the undesired duplicates itself.

Inner join on ConCat fields

I have table A
Code Range
A 12569
B 18175
C 478931
And Table B
id Type
A12569 0
B18175 1
C478931 0
How can I concatenate the two fields of the first table, in order to join them with the second table.
I have tried with the following query
SELECT concat(A.code,B.Range),b.Type FROM DB.tableA A
inner join DB.tableB B
on Concat(A.code,B.Range)= B.id;
Just concatenate the two columns:
select *
from table_a a
join table_b b on a.code||range = b.id;
The above is standard SQL - not all DBMS respect that though and use a different operator to concatenate strings.
SQL Server:
Select a.Code+b.Range as id, b.Type from TableA a inner join tableB b on a.Code + b.Range = b.id
Untested but should work - presumption is all columns are varchar or nvarchar. May need to add some casting on the range field if that's not the case.

Separated JOIN form main INNER JOINS's

I want to INNER JOIN some tables and then insert a condition where the entries of a table are dependant on another table (that was not joined with the others)
Something like this:
SELECT * FROM TABLE_A AS a
INNER JOIN TABLE_B AS b ON b.id_b=a.id_a
INNER JOIN TABLE_C AS c ON c.id_c=b.id_b
Now I want to add a condition (possibly a "WHERE" clause) that only selects the values in a field in TABLE_C that match another condition, the existence of a value in a field in TABLE_D
Possible statement:
WHERE c.code=d.another_code AND d.reg_number LIKE 999%
How do i declare in the query the TABLE_D, since I do not want to Join it with the others?
In other words, I want to intersect 3 sets (A,B,C) and the other one (set D) is intersected only with set C
The title of the question Run-time error '13': ... doesn't seem to match the content so I'll just answer the SQL part.
Maybe this is what you want?
SELECT * FROM TABLE_A AS a
INNER JOIN TABLE_B AS b ON b.id_b=a.id_a
INNER JOIN TABLE_C AS c ON c.id_c=b.id_b
WHERE c.code = -- or possiby IN instead of =
(SELECT another_code FROM TABLE_D WHERE another_code LIKE '999%')
If the subquery can return multiple rows you need to use WHERE c.code IN instead of WHERE c.code =

Oracle SQL WITH clause select joined column

SQL:
WITH joined AS (
SELECT *
FROM table_a a
JOIN table_b b ON (a.a_id = b.a_id)
)
SELECT a_id
FROM joined
returns invalid identifier.
How can you select joined column when using WITH clause? I have tried aliases, prefixing and nothing worked. I know I can use:
WITH joined AS (
SELECT a.a_id
FROM table_a a
JOIN table_b b ON (a.a_id = b.a_id)
)
SELECT a_id
FROM joined
but I need this alias to cover all fields.
Only way I managed to meet this condition is using:
WITH joined AS (
SELECT a.a_id a_id_alias, a.*, b.*
FROM table_a a
JOIN table_b b ON (a.a_id = b.a_id)
)
SELECT a_id_alias
FROM joined
but it is not perfect solution...
You can use the effect of the USING clause when joining the tables.
When you join tables where the join columns have the same name (as it is the case with your example), the USING clause will return the join column only once, so the following works:
with joined as (
select *
from table_a a
join table_b b using (a_id)
)
select a_id
from joined;
SQLFiddle example: http://sqlfiddle.com/#!4/e7e099/2
I don't think you can do this without aliases. The result of the "joined" query has two fields, both named a_id. Unless you alias one (or both), as you did in your final query, the outer query has no idea which a_id you are referring to.
Why is your final query not a "perfect" solution?
You can probably use alias as below:
WITH JOINED AS (
SELECT A.A_ID A_A_ID, B.A_ID B_A_ID,
A.FIELD_NAME1 A_FIELDNAME1, A.FIELDNAME2 A_FIELDNAME2,A.FIELDNAME_N A_FIELDNAME_N,
B.FIELD_NAME1 B_FIELDNAME1, B.FIELDNAME2 B_FIELDNAME2,B.FIELDNAME_N B_FIELDNAME_N,
FROM TABLE_A A
JOIN TABLE_B B ON (A.A_ID = B.A_ID)
)
SELECT A_A_ID, B_A_ID
FROM JOINED
IT IS ALWAYS A GOOD PRACTICE TO AVOID USING SELECT *

Factor where clauses into subqueries

I'm wondering if its always possible in SQL to factor a where condition through a join to a subquery. For instance, if I have
select ... from a join b on ... where p and q
and p pertains only to a, q to b, then can I always rewrite as?
select ... from (select ... from a where p) as a join (select ... from b where q) as b on ...
Thanks!
[Notes: 1) I'm using postgres in case this affects the answer. 2) Readability is not an important consideration, as these are automatically generated queries. Edit: 3) I'm not only interested in inner join but other joins as well.]
In general the query 1:
SELECT ...
FROM TableA
JOIN TableB ON <SomeForeignKey>
JOIN TableC ON <SomeForeignKey>
WHERE <SomeConditionOnTableA> AND
<SomeConditionOnTableB> AND
<SomeConditionOnTableC>
... is equivalent to the query 2:
SELECT ...
FROM TableA
JOIN TableB ON <SomeForeignKey> AND <SomeConditionOnTableB>
JOIN TableC ON <SomeForeignKey> AND <SomeConditionOnTableC>
WHERE <SomeConditionOnTableA>
But the same is not true if instead of (INNER) JOINs you use OUTER JOINs. With OUTER JOINs the equivalency holds for very simple conditions that match NOT NULL column values, like:
name='value'
name LIKE '%value%'
number < const
field IN (...)
Notice that these are all conditions that make the OUTER JOINs moot anyway, as they are filtering out rows that have NULL values in the envolved columns... so they would filter out also the rows added by the OUTER JOIN not retrieving anything from the joined table.
But the equivalency breaks if you use OUTER JOINs and start comparing column values with NULLs or comparing expressions that may envolve NULLs.
For example, taking this query (formatted as query 1):
SELECT ...
FROM TableA a
LEFT JOIN TableB b ON <SomeForeignKey>
LEFT JOIN TableC c ON <SomeForeignKey>
WHERE a.somefield = 'whatever'
AND b.name IS NOT NULL
AND c.somenumber >100
In this case the filter is applied after having resolved the OUTER JOIN, and it eliminates both the rows that exist in TableB and have a NULL name, but also removes the rows that where added by the OUTER JOIN not finding a matching row in TableB. This is not equivalent to the query 2 format:
SELECT ...
FROM TableA a
LEFT JOIN TableB b ON <SomeForeignKey> AND b.name IS NOT NULL
LEFT JOIN TableC c ON <SomeForeignKey> AND c.somenumber >100
WHERE a.somefield = 'whatever'
In this case the filter is applied to TableB before resolving the OUTER JOIN. TableB rows that have a NULL name are eliminated by the filter, but reintroduced by the LEFT JOIN. So this query might contain rows that the former does not.
I would say yes, I can't think of a situation where it is not possible. WHERE in it self can be replaced with a join:
select ... from A where x=10
<=>
select ... from A join ( values (10) ) B (x) on A.x = B.x
Perhaps off topic, but for transformations in general Vadim Tropashko (http://arxiv.org/abs/cs/0501053) shows that it is possible to reduce the set of classic relational algebra operators to two binary operations: natural join and generalized union