Is it relevant to add verification on both 'on join' and 'where'? - sql

I would like to know if there is any difference between these queries:
1)
SELECT
...
FROM A
JOIN B on B.AId = A.Id and B.X = #x
WHERE
A.Id = 1
and B.X = #x
2)
SELECT
...
FROM A
JOIN B on B.AId = A.Id
WHERE
A.Id = 1
and B.X = #x
3)
SELECT
...
FROM A
JOIN B on B.AId = A.Id and B.X = #x
WHERE
A.Id = 1

Because you are using an INNER JOIN there is no difference. Records are only kept where the join condition is true. If you filter results from b before the join (by specifying in the ON) or afterwards (by specifying in the WHERE) you'll end up with the same result set. (before and after is sort of arbitrary here, but it helps to think through it that way)
Also, your first query is not great since you filter on #x in two different spots. That is superfluous. My preference would be option 2.

If you go back to the origins of SQL there was no specific "join" syntax, instead all filtering was part of the where clause
SELECT
...
FROM A, B
WHERE
A.Id = 1
and B.AId = A.Id
and B.X = #x
So, whilst I absolutely don't wish to promote this older style syntax, it may help you understand that there really is no difference to your options 2 and 3 to the one I have just presented.
Your option 1 has a repeated predicate (and B.X = #x) which most optimizers will probably ignore, but even that option produces that same result.

Filtering in where or Inner Join will do the same job. 'Where' filtering is preferred over filtering in the 'Join'(will be looking good). It may have impact when the join is not 'Inner Join', Say 'Left Outer Join' or 'Right Outer Join'
Which SQL query is faster? Filter on Join criteria or Where clause?

Related

What kind of join is used in a Vertica UPDATE statement?

Vertica has an interesting update syntax when updating a table based on a join value. Instead of using a join to find the update rows, it mandates a syntax like this:
UPDATE a
SET col = b.val
where a.id = b.id
(Note that this syntax is indeed mandated in this case, because Vertica prohibits us from using a where clause that includes a "self-join", that is a join referencing the table being updated, in this case a.)
This syntax is nice, but it's less explicit about the join being used than other SQL dialects. For example, what happens in this case?
UPDATE a
SET col = CASE 0 if b.id IS NULL ELSE b.val END
where a.id = b.id
What happens when a.id has no match in b.id? Does a.col not get updated, as though the condition a.id = b.id represented an inner join of a and b? Or does it get updated to zero, as if the condition were a left outer join?
I think Vertica uses the Postgres standard for this syntax:
UPDATE a
SET col = b.val
FROM b
whERE a.id = b.id;
This is an INNER JOIN. I agree that it would be nice if Postgres and the derived databases supported explicit JOINs to the update table (as some other databases do). But the answer to your question is that this is an INNER JOIN.
I should note that if you want a LEFT JOIN, you have two options. One is a correlated subquery:
UPDATE a
SET col = (SELECT b.val FROM b whERE a.id = b.id);
The other is an additional level of JOIN (assuming that id is unique in a):
UPDATE a
SET col = b.val
FROM a a2 LEFT JOIN
b
ON a2.id = b.id
WHERE a.id = a2.id;

Joins in Oracle: Which field on which side of an = sign?

When joining tables with either the ANSI-89 (old) or the ANSI-92 ("new") method of joining tables, does it matter which side you place the fields from the 2 joining tables.
For example, is it better to do:
From
TABLE_1 A
Join
TABLE_2 B
on A.ID = B.ID
Or is the following better?
on B.ID = A.ID
Is it simply aesthetics? Or does it effect how the joins work?
EDIT: For further clarification, what about Left Joins? For example:
From
TABLE_1 A
Left Join
TABLE_2 B
on A.ID = B.ID
Is this the same as
on B.ID = A.ID
However, if using ANSI-89 Where A.ID = B.ID (+) is NOT the same as Where B.ID = A.ID (+) since the second joins A ONTO B?
It makes no difference. The only time the order matters is when you are doing LEFT and RIGHT OUTER joins, but those keywords all fall before the ON keyword.
The = operator is symmetric, so a.id = b.id is exactly the same as b.id = a.id. Personally, I prefer having the fields from the driving table (the one in the FROM clause) on the left hand side of the operator, but that's purely an aesthetic preference.

How to use oracle outer join with a filter where clause

If i write a sql:
select *
from a,b
where a.id=b.id(+)
and b.val="test"
and i want all records from a where corresponding record in b does not exist or it exists with val="test", is this the correct query?
You're much better off using the ANSI syntax
SELECT *
FROM a
LEFT OUTER JOIN b ON( a.id = b.id and
b.val = 'test' )
You can do the same thing using Oracle's syntax as well but it gets a bit hinkey
SELECT *
FROM a,
b
WHERE a.id = b.id(+)
AND b.val(+) = 'test'
Note that in both cases, I'm ignoring the c table since you don't specify a join condition. And I'm assuming that you don't really want to join A to B and then generate a Cartesian product with C.
Move the condition into the JOIN clause and use the ANSI standard join pattern.
SELECT NameYourFields,...
FROM A
LEFT OUTER JOIN B
ON A.ID = B.ID
AND B.VAL = 'test'
INNER JOIN C
ON ...
A LEFT OUTER JOIN is one of the JOIN operations that allow you to specify a join clause. It preserves the unmatched rows from the first (left) table, joining them with a NULL row in the shape of the second (right) table.
So you can do as follows :
SELECT
FROM a LEFT OUTER JOIN b
ON a.id = b.id
--Note that you have used double quote "test" which is not used for varchar in SQL you should use single quote 'test'
AND b.val = 'test';
SELECT * FROM abc a, xyz b
WHERE a.id = b.id
AND b.val = 'test'

Using Join based on condition

Can anyone please explain me how can we use join on the basis of condition.
Lets say i am filtering data on the basis of a condition now my concern is if a particular BIT type parameters value is 1 then the data set include one more join else return same as earlier.
Here is three tables A,B,C
now i want to make a proc which has the #bool bit parameter
if #bool=0
then
select A.* from A
inner join B on B.id=A.id
and if #bool=1
then
select A.* from A
INNER JOIN B on B.id=A.id
inner join C on C.id=A.id
Thanks In Advance.
What you have will work (certainly in a SPROC in MS SQL Server anyway) with minor mods.
if #bool=0 then
select A.* from A
inner join B on B.id=A.id
else if #bool=1 then -- Or just else if #boll is limited to [0,1]
select A.* from A
INNER JOIN B on B.id=A.id
inner join C on C.id=A.id
However, the caveat is that SQL parameter sniffing will cache a plan for the first path it goes down, which won't necessarily be optimal for other paths through your code.
Also, if you do take this 'multiple alternative query' approach to your procs, it is generally a good idea to ensure that the column names and types returned are identitical in all cases (Your query is fine because it is A.*).
Edit
Assuming that you are using SQL Server, an alternative is to use dynamic sql:
DECLARE #sql NVARCHAR(MAX)
SET #sql = N'select A.* from A
inner join B on B.id=A.id'
IF #bool = 1
SET #sql = #sql + N' inner join C on C.id=A.id'
sp_executesql #sql
If you need to add filters etc, have a look at this post: Add WHERE clauses to SQL dynamically / programmatically
select A.* from A
inner join B on B.id = A.id
left outer join C on C.id = A.id and #bool = 1
where (#bool = 1 and C.id is not null) or #bool = 0
The #bool = 1 "activates" the left outer join, so to speak, and turns it, in effect, into an inner join by applying it in the WHERE clause, too. If #bool = 0 then the left outer join returns nothing from C and removes the WHERE restriction.
Try the following query
SELECT A.*
FROM A
INNER JOIN B on B.id=A.id
INNER JOIN C on C.id=A.id and #bool=1
You do it using a union:
SELECT A.*
FROM A
INNER JOIN B on B.id=A.id
WHERE bool = 0
UNION ALL
SELECT A.*
FROM A
INNER JOIN B on B.id=A.id
INNER JOIN C on C.id=A.id
WHERE bool = 1
I'm assuming that bool is stored in table A or B.

Oracle outer join with filter condition on the second table

Is there any condition under which the result sets will be different from the following two statements?
select * from a,b where a.id = b.id and b.name = 'XYZ'
select * from a,b where a.id =b.id(+) and b.name = 'XYZ'
I think in both cases it will bring the common rows from a and b where b.name = 'XYZ'. So a.id = b.id(+) has no meaning.
No, there is no condition under which the result sets will be different.
But your assumption "a.id = b.id(+) has no meaning" is not 100% correct. It has a meaning, because it defines the join, otherwise this would be a cartesian product of a and b with all rows from a and b.name = 'XYZ'.
What has no effect is the (+), because the statement is "semantically" wrong. It makes no sense to outer join on id but to join on name.
Usually something like that is wanted:
select * from a,b where a.id =b.id(+) and b.name(+) = 'XYZ';
Short example at http://www.sqlfiddle.com/#!4/d19b4/15