Join to a table only when column value is true - sql

I am using SQL Server 2005. I am trying to join 2 tables together, but only when a column value in the main table is true. Like this:
select * from T1
join T2 on T1.value = T2.value
where T2.value2 = 'variable2'
and T2.value3 = 'variable3'
There is a column value in T1 which says if I have to use the values in T2. I could to a case around the where clause, but it will always join to the table, and if the value in T1 is false, there are no values in T2 to join to, so the select returns no rows.
You can't put a case around the join, so I am a little bit stuck with this ... can anyone help ?

select *
from T1
join T2
on T1.value = T2.value
and T1.booleancolumn = 1
where T2.value2 = 'variable2'
and T2.value3 = 'variable3';

Similar to what Dave posted, but I also read that to mean you want to actually substitute values in the results. In that case:
SELECT
COALESCE(T2.Value, T1.Value) AS Value,
COALESCE(T2.Value2, T1.Value2) AS Value2,
COALESCE(T2.Value3, T1.Value3) AS Value3
FROM T1
LEFT JOIN T2 ON T2.value = T1.value
AND T2.Value2= #Variable2 AND T2.Value3 = #Variable3
Note that I'm treating your constants as real variables, too.

Dave Marke is right, but more generaly...
conditional join is answer to your question, try find some resources on web for example
http://weblogs.sqlteam.com/jeffs/archive/2007/04/03/Conditional-Joins.aspx
http://bytes.com/groups/ms-sql/641690-difference-condition-join-where
it is very powerful technique to make joins depending on data in tables

Perhaps I have misunderstood your question, but here's my guess.
I think you can use a case in the WHERE.
select * from T1
join T2 on T1.value = T2.value
where T2.value2 = case T1.useT2 when 'yes' then 'variable2' else T2.value2 END
and T2.value3 = case T1.useT2 when 'yes' then 'variable3' else T2.value3 END

Very similar to what Dave said, although I would put the booleancolumn check into the WHERE so something like this
SELECT * FROM T1
INNER JOIN T2
ON T1.Value = T2.Value
WHERE T2.Value2 = 'variable2'
AND T2.Value3 = 'variable3'
AND T1.booleancolumn = 1

What, if any, are the performance considerations related to conditional joins, I wonder? Is it equivalent to a UNION like this:
SELECT T1.*
FROM T1
WHERE T1.use_t2 = FALSE
AND T1.value2 = 'variable2'
AND T1.value3 = 'variable3'
UNION ALL
SELECT T2.*
FROM T1 JOIN T2 ON T1.value = T2.value
WHERE T1.use_t2 = TRUE
AND T2.value2 = 'variable2'
AND T2.value3 = 'variable3'

Related

Skip the joins based on the condition without dynamic query

I am having a scenerio like i am having two table with the name tbl1 and tb2
Select * from tbl1 t1 inner join tb2 t2 on t1.Id = t2.id
The above sample query here i need to achive is that i need to perform this inner join based on the condition. (i.e) I will pass input parameter IsJoin as true means, i can perform inner join else not. I am not preferring dynamic query. Kindly let me know if there is any other way to achieve this.
Thanks in advance
There's just one way to do that then - using IF and ELSE statements
IF <YOUR CONDITION>
BEGIN
SELECT *
FROM tbl1 t1
INNER JOIN tb2 t2
ON t1.Id = t2.id;
END
ELSE
BEGIN
SELECT *
FROM tbl1 t1;
END
If it's just few conditions, then it's fine to do this using multiple statements, however if it's tons of joins based on conditions - it's easier to maintain Dynamic SQL. And it becomes much more readable.
Try this way:
declare #IsJoin numeric(1,0)
select #IsJoin = 1
Select * from tbl1 t1
left join tb2 t2 on t1.Id = t2.id
and #IsJoin = 1
If you need to preserve all columns of t1 and t2 whether join or not
DECLARE #IsJoin bit = 1 -- 1 for true; 0 for false
SELECT
*
FROM
tbl1 t1
LEFT OUTER JOIN tbl2 t2 on t1.Id = t2.id and #IsJoin = 1
WHERE
(#IsJoin = 0 OR t2.id is not null) -- Keep the inner join behavior

Null<> Number displays nothing even if for id we have null in one and number in other

Sorry if this is very basic.
Here is what i noticed
Here are the tables:
Table1 Table2
ID Value ID Value
1 (null) 1 0
2 2 2 2
3 (null) 3 3
So i used the following statement:
Select T1.ID,T1.Value,T2.value
from
Table1 T1,
Table2 T2
where
T1.ID=T2.ID
and T1.Value<>T2.Value;
I was expecting the output to show 1,3 ID but it showed nothing not i am confused suppose i want to see all values when one table has null for other table value how can i do that.
Well, the problem is that comparisons to NULL always result in FALSE, except for IS NULL. So the clause should be:
where T1.ID=T2.ID and
coalesce(T1.Value, t2.value - 1) <> coalesce(T2.Value, t1.value -1);
Or something that matches the NULL values.
By the way, you should also use proper join syntax. So, the query should look more like:
Select T1.ID,T1.Value,T2.value
from Table1 T1 join
Table2 T2
on T1.ID=T2.ID and
((T1.Value <> T2.Value) or
(t1.value is not null and t2.value is null) or
(t1.value is null and t2.value is not null)
);
you have to use LEFT JOIN rather than INNER JOIN because you want to find non matching values.
Select t1.ID,T1.Value,T2.value
from Table1 T1
LEFT JOIN Table2 T2
ON T1.ID=T2.ID AND
t1.value = t2.value
where t2.value IS NULL
SQLFiddle Demo
To fully gain knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
Select T1.ID,T1.Value,T2.value
from
Table1 T1,
Table2 T2
where
T1.ID=T2.ID
and (T1.Value<>T2.Value OR (T1.Value IS NULL AND T2.Value IS NOT NULL) OR (T2.Value IS NULL AND T1.Value IS NOT NULL));
Null values are special. You can do it with a complex query like
Select T1.ID,T1.Value,T2.value
from
Table1 T1,
Table2 T2
where
T1.ID=T2.ID
and ((t1.value is null or t2.value is null)
and !(t1.value is null and t2.value is null)
or t1.value <> t2.value);
Link to SQLFiddle
Note that the syntax is going to be different, depending on the flavor of SQL that you are using.

Join query between 2 tables, the first with several fields refering to the same fields in the other

I have to build an application on an existing SQL database and I came upon this situation.
There's a table (call it T1) where several fields reference values from another table (T2), which basically is made up of just 2 fields, Id and Name. As a consequence, T2 holds data of different nature and meaning, because the fields in T1 that relate to it are of very different kinds. (This seems to me an unusual design.)
My question: given this design, how I can build a join query in order to get the value of T2.Name related to each T1 field.
EDIT
I could get what I want by doing one query per field:
SELECT t2.name AS name1
FROM t1
INNER JOIN t2
ON t1.field1 = t2.id;
SELECT t2.name AS name2
FROM t1
INNER JOIN t2
ON t1.field2 = t2.id;
SELECT t2.name AS name3
FROM t1
INNER JOIN t2
ON t1.field3 = t2.id;
But this is nonsense. So how could I pack all this in one single query?
You need to alias references to t2 to get corresponding names:
SELECT alias1.name AS name1,
alias2.name AS name2,
alias3.name AS name3
FROM t1
INNER JOIN t2 alias1
ON t1.field1 = alias1.id
INNER JOIN t2 alias2
ON t1.field2 = alias2.id
INNER JOIN t2 alias3
ON t1.field3 = alias3.id;
You might want to replace inner with left joins if foreign keys are nullable.
Is there any reason you can't use ORs in your join? So:
SELECT t2.name AS name3
FROM t1, t2
WHERE t1.field1 = t2.id
OR t1.field2 = t2.id
OR t1.field3 = t2.id;
If for some reason you cant then you can use UNION to combine the result of all the queries in a single query. I don't know which RDBMS your using but for postgres you can find information here:
http://www.postgresql.org/docs/8.3/static/queries-union.html
For any other a quick google of the DBMS name and "UNION" should give you what you need.
Without seeing the table structures, you could do something like this:
SELECT t1.col1,
t1.col2,
t1.id as t1_id,
t2.id as t2_id,
t2.name as t2_name
FROM t1
INNER JOIN t2
ON t1.id = t2.id
Since you are joining the tables, you will just give a different alias for the columns that appear in both tables.
Based on your update, you should be able to consolidate those 3 queries into one:
SELECT t2.name AS name1
FROM t1
INNER JOIN t2
ON t1.field1 = t2.id
OR t1.field2 = t2.id
OR t1.field3 = t2.id
try something like this,
SELECT t2.name AS name1,
(case when t1.field1 = t2.id then 'Type1' when t1.field2=t2.id then 'Type2' else 'Type3' end) as Type FROM t1 INNER JOIN t2 ON t1.field1 = t2.id or
t1.field2=t2.id or t1.field3=t2.id

Can I use the exists function in the select part of an SQL query?

I need to run a query where one of the fields returned is a yes or no if there is a row in another table matching one of the key fields in the first table.
Sounds like a job for join, except the second table is one to many and I just need to know if there are zero or a non zero number of rows in the secondary table.
I could do something like this:
select t1.name, t1.id, (select count(1) from t2 where t1.id=t2.id) from t1
but I'd like to avoid making an aggregate subquery if possible.
It was mentioned to me that I could use the exists() function, but I'm not seeing how to do that in a select field.
This is sybase 15 by the way.
You could still do the JOIN, something like this:
SELECT t1.name, t1.id, CASE WHEN t2.id IS NULL THEN 0 ELSE 1 END Existst2
FROM t1
LEFT JOIN (SELECT id FROM t2 GROUP BY id) t2
ON t1.id = t2.id
ahhh, I got it from another stackoverflow quetion...
case when exists (select * from t2 where t1.id = t2.id) then 1 else 0 end
I am just writing down the syntax here:
if exists (select * from table1 t1 inner join table1 t2 on t1.id = t2.id )
select * from table2
How about this query ( Work with all databases )
select t1.name, t1.id, 'Y' as HasChild
from t1
where exists ( select 1 from t2 where t2.id = t1.id)
UNION
select t1.name, t1.id, 'N' as HasChild
from t1
where NOT exists ( select 1 from t2 where t2.id = t1.id)

SQL Server 2005 - Using CASE inside Stored Procedure

I'm using a select statement inside a stored procedure. All I need to do is based on the value of a parameter I've to use either RIGHT JOIN or INNER JOIN. Please anyone there help me to achieve this. Many Thanks in Advance..
SELECT FLD1, FLD2
FROM TBL1 C (NOLOCK)
CASE
WHEN #SHOW = 156 THEN INNER
ELSE RIGHT JOIN TBL2 IC (NOLOCK) ON C.FLD3 = IC.FLD4
END
Is it correct? What would be the right way of doing this?
You could use IF statements:
DECLARE #Param VARCHAR(10)
SET #Param = 'RIGHT'
IF (#Param = 'RIGHT')
SELECT t1.Something
FROM Table1 t1
RIGHT JOIN Table2 t2 ON t1.ID = t2.ID
WHERE ...
ELSE IF (#Param = 'INNER')
SELECT t1.Something
FROM Table1 t1
INNER JOIN Table2 t2 ON t1.ID = t2.ID
WHERE ...
Or could be done as one SELECT (not necessarily best performance, be sure to test), something like:
SELECT t1.Something
FROM Table1 t1
RIGHT OUTER JOIN Table2 t2 ON t1.ID = t2.ID
WHERE (#Param = 'RIGHT') OR (#Param = 'INNER' AND t1.ID IS NOT NULL)
Theres more than enough information on the case statement out there, this should get you started.