When I write an exist query in ORACLE JOIN syntax like this, it works fine as expected.
Select * from TableA
where not exists (Select 1 from TableB where TableB.Id = TableA.TableBForeignKeyId)
When i write it as ANSI JOIN syntax, it doesn't work.
Select * from TableA
where not exists (Select 1
from (TableA
INNER JOIN TableB
on TableA.TableBForeignKeyId = TableB.Id))
On the ANSI JOIN version, TableA behave not like the upper querys TableA, because of that, the complete query returns no rows.
Not: There is only one row on TableA that has no reference on TableB.
This query should return one row of TableA.
Why ANSI JOIN behave like this?
The syntax you have written in the first query is good: i.e.
Select * from TableA
where not exists (Select 1 from TableB where TableB.Id = TableA.TableBForeignKeyId)
In the second query, TableA of the inner query will not refer to the outer TableA and hence you are not getting the desired result.
Why you are not happy with the first query?
If you are looking for some other way of writing the query then you can use the following query:
Select * from TableA
where TableA.TableBForeignKeyId not in (Select TableB.Id
from TableB )
Cheers!!
The two queries are not similar at all.
The first is a correlated subquery. The WHERE condition refers to the outer query.
The second is an uncorrelated subquery. There is no connection to the outer query. In this case, the subquery returns a single value, independent of the outer query. If it returns no rows, then the overall query returns no rows. If it returns one or more rows, then the overall query returns multiple rows.
Both are valid, correct syntax. You should use the one you want, which would normally be the correlated subquery.
Related
I am using Sqlite3. What is the most efficient way to:
Execute a query to join two tables t1 and t2. The query is designed to keep all of the columns from t1, and just add columns from t2. It will either keep all rows (left outer join) or just keep the matching rows.
Using the result, update t1 in the database to look exactly like the results of the query.
Try this:
select a.*, b.hostname, b.mac
from tablea a left join
tableb b on a.ip_address = b.ip
I have a SQL query similar as below:
select *
from TableA
left outer join TableB on...
left outer join TableC on...
...
left outer join TableN on...
where
TableA.id in (subquery);
This query takes a long time to execute and I checked the execution plan of it and and found out that it did the joins first and then the where. However, the joins takes long time to finish. I run the same query against Oracle and Oracle did the optimization so that it does the 'where' part together with the joins and so that the time is much short.
My question is: how can I optimize the SQL query so that Postgres can do the 'where' part first?
PS: I cannot add the subquery into the 'from' part using an inner join because I am using Hibernate and it doesn't support subquery in 'from' part.
As already discussed widely in the comments to your post there is a possibility that the "FROM (subquery) tblalias" approach might still work, so here it is as pseudocode again:
select * from (
select * from TableA where id in (subquery)
) tblA
left outer join TableB on...
left outer join TableC on...
...
left outer join TableN on...
But - who knows for definite, as pseudocode cannot be tested ...
I have read a number of posts from SO and I understand the differences between filtering in the where clause and on clause. But most of those examples are filtering on the RIGHT table (when using left join). If I have a query such as below:
select * from tableA A left join tableB B on A.ID = B.ID and A.ID = 20
The return values are not what I expected. I would have thought it first filters the left table and fetches only rows with ID = 20 and then do a left join with tableB.
Of course, this should be technically the same as doing:
select * from tableA A left join table B on A.ID = B.ID where A.ID = 20
But I thought the performance would be better if you could filter the table before doing a join. Can someone enlighten me on how this SQL is processed and help me understand this thoroughly.
A left join follows a simple rule. It keeps all the rows in the first table. The values of columns depend on the on clause. If there is no match, then the corresponding table's columns are NULL -- whether the first or second table.
So, for this query:
select *
from tableA A left join
tableB B
on A.ID = B.ID and A.ID = 20;
All the rows in A are in the result set, regardless of whether or not there is a match. When the id is not 20, then the rows and columns are still taken from A. However, the condition is false so the columns in B are NULL. This is a simple rule. It does not depend on whether the conditions are on the first table or the second table.
For this query:
select *
from tableA A left join
tableB B
on A.ID = B.ID
where A.ID = 20;
The from clause keeps all the rows in A. But then the where clause has its effect. And it filters the rows so on only id 20s are in the result set.
When using a left join:
Filter conditions on the first table go in the where clause.
Filter conditions on subsequent tables go in the on clause.
Where you have from tablea, you could put a subquery like from (select x.* from tablea X where x.value=20) TA
Then refer to TA like you did tablea previously.
Likely the query optimizer would do this for you.
Oracle should have a way to show the query plan. Put "Explain plan" before the sql statement. Look at the plan both ways and see what it does.
In your first SQL statement, A.ID=20 is not being joined to anything technically. Joins are used to connect two separate tables together, with the ON statement joining columns by associating them as keys.
WHERE statements allow the filtering of data by reducing the number of rows returned only where that value can be found under that particular column.
I have two tables: tableA and tableB. TableA has a field idA and tableB has a record idB and idBPtrA where idBptrA is a pointer to tableA (one of the idA).
I want, using postgres, to select records from a TableA that have the minimal number of records in tableB.
Something like:
select idA,idB,count(idBPtrA) as c
from tableA,tableB
group by idBPtrA
where idA=idB order by c
This of course doesn't work and gives me an error, but I think it should be very similar to that... Any ideas?
I think this is the query that you want:
select a.idA, count(b.idB) as c
from tableA a left join
tableB b
on a.idA = b.idptrA
group by a.idA
order by c;
Notes:
Use table aliases and qualify column names (especially if you are learning SQL).
Learn and use proper, explicit JOIN syntax. Simple rule: Never use commas in the FROM clause.
I am trying to run a left join on 2 tables. I do not have a group by and the only where condition i have is on the second table. But, the returned rows are less than the first table. isn't the left join suppose to bring all the data from the first table?
Here is my SQL:
select *
from tbl_a A left join tbl_b B
ON
A.Cnumber=B.Cnumber
and A.CDNUmber=B.CDNumber
and abs(A.duration - B.Duration)<2
and substr(A.text,1,3)||substr(A.text,5,8)||substr(A.text,9,2)=substr(B.text,1,8)
where B.fixed = 'b580'
There are 140,000 records in table A but the result returned is less than 100,000 records. What is the problem and how can I solve it?
As soon as you put a condition in the WHERE clause that references the right table and doesn't accommodate the NULLs that will be produced when the join is unsuccessful, you've transformed it (effectively) back into an INNER JOIN.
Try:
where B.fixed = 'b580' OR B.fixed IS NULL
Or add this condition to the ON clause for the JOIN.
You should add the where clause to the join:
select *
from tbl_a A left join tbl_b B
ON
A.Cnumber=B.Cnumber
and A.CDNUmber=B.CDNumber
and abs(A.duration - B.Duration)<2
and substr(A.text,1,3)||substr(A.text,5,8)||substr(A.text,9,2)=substr(B.text,1,8)
and B.fixed = 'b580'
If you use where statemen all records where b is not existing will not returned.