LEFT JOIN ambiguous columns into one column in SQL statement? - sql

Is it possible to LEFT JOIN two columns of a same nature, i.e. join t2.Name and t3.Name into a single column (dataproperty) Name in a T-SQL statement?
SELECT t1.ID,
t1.RowID,
t2.name,
t3.Name
FROM MasterTable T1
LEFT OUTER JOIN RightTable1 T2
ON T1.RowID = T2.ID
LEFT OUTER JOIN RightTable2 T3
ON T1.RowID = T3.ID
WHERE t1.ID= " & ID & ";
...or do I have to load the tables into separate datasets and join them programatically (for each ... next) into a new dataset?
Regards,
Libor

It depends on hat you mean by "join" - here are a few possibilities:
If one is null and the other isn't, use ISNULL:
SELECT DISTINCT
t1.ID,
t1.RowID,
ISNULL(t2.name, t3.Name) Name
FROM MasterTable T1
LEFT OUTER JOIN RightTable1 T2 on T1.RowID = T2.ID
LEFT OUTER JOIN RightTable2 T3 on T1.RowID = T3.ID
If you want to concatenate them:
SELECT DISTINCT
t1.ID,
t1.RowID,
t2.name + t3.Name Name
FROM MasterTable T1
LEFT OUTER JOIN RightTable1 T2 on T1.RowID = T2.ID
LEFT OUTER JOIN RightTable2 T3 on T1.RowID = T3.ID
If you want two rows (a UNION):
SELECT DISTINCT
t1.ID,
t1.RowID,
t2.Name
FROM MasterTable T1
LEFT OUTER JOIN RightTable1 T2 on T1.RowID = T2.ID
UNION ALL
SELECT DISTINCT
t1.ID,
t1.RowID,
t3.Name
FROM MasterTable T1
LEFT OUTER JOIN RightTable2 T3 on T1.RowID = T3.ID
Note that DISTINCT is necessary because unless you can relate T2 and T3 you basically do a cross join (cartesian product) between T2 and T3 so you need to eliminate the duplicates that are created.

SELECT t1.ID,
t1.RowID,
t2.name + t3.Name AS JoinedName
FROM MasterTable T1
LEFT OUTER JOIN RightTable1 T2
ON T1.RowID = T2.ID
LEFT OUTER JOIN RightTable2 T3
ON T1.RowID = T3.ID
WHERE t1.ID= " & ID & ";

Related

Select in Where Clause

Well, I did some research before posting here and I haven't find the correct solution.
Here is my SQL, I would like to improve the performance and remove select clause after where if possible by join or any other way.
The catch is Table1 is the first table to join and it is the same table in Where clause. I am not sure whether I am doing it right or wrong. I would like to know if there is any other efficient way to get the same result
SELECT T3.Id, T3.Name
FROM dbo.Table1 T1
JOIN dbo.Table2 T2 ON T1.Id = T2.Id
JOIN dbo.Table3 T3 ON T2.Name = T3.Name
WHERE T1.fId = (SELECT fId FROM dbo.Table1 WHERE Id = 1)
You can do this with a simple join:
SELECT T3.Id, T3.Name
FROM dbo.Table1 T1
inner JOIN dbo.Table2 T2 ON T1.Id = T2.Id
inner JOIN dbo.Table3 T3 ON T2.Name = T3.Name
inner join dbo.Table1 T4 on T4.fId = T1.fId and T4.Id= 1
Because you are using a WHERE clause in the subquery with a fixed value, you can simply replace the whole query by the value used
SELECT T3.Id, T3.Name FROM dbo.Table1 T1
JOIN dbo.Table2 T2 ON T1.Id = T2.Id
JOIN dbo.Table3 T3 ON T2.Name = T3.Name
WHERE T1.Id = 1
See if you want output of only T3 table then use "Exists" clause
SELECT T3.Id, T3.Name
FROM dbo.Table3 T3
where exists(
select t2.id from dbo.Table2 T2
inner join dbo.Table1 T1 on T1.Id = T2.Id
where T2.Name = T3.Name
and t1. Id = 1
)

Left Join; Only if there is at least one matching record

I need to join two pairs of tables. If there is an ID in Table1 that can also be found in Table3 I need to join the tables. If there is no matching ID from Table1 in Table3, I need to not join the tables.
Ex.
If there is at least one id in Table1 in Table3; do something that is effectively this:
SELECT *
FROM Table1 AS t1
INNER JOIN Table2 AS t2 ON t1.ID = t2.ID
LEFT JOIN Table3 AS t3 ON t1.ID = t3.ID
LEFT JOIN Table4 AS t4 ON t3.ID = t4.ID
If there are no IDs that match between Table1 and Table3; do something that is effectively this:
SELECT *
FROM Table1 AS t1
INNER JOIN Table2 AS t2 ON t1.ID = t2.ID
Just translating your question into SQL, you can do this:
IF EXISTS(SELECT * FROM Table1 T1 INNER JOIN Table3 T3 ON T1.ID=T3.ID)
SELECT *
FROM Table1 AS t1
INNER JOIN Table2 AS t2 ON t1.ID = t2.ID
LEFT JOIN Table3 AS t3 ON t1.ID = t3.ID
LEFT JOIN Table4 AS t4 ON t3.ID = t4.ID
ELSE
SELECT *
FROM Table1 AS t1
INNER JOIN Table2 AS t2 ON t1.ID = t2.ID

Oracle SQL: JOIN by dblink

I use next SQL-query in Oracle DB:
SELECT T1.*,
T3.*
FROM MyTable1 T1
INNER JOIN MyTable2 T2 ON T2.Id1 = T1.Id
LEFT JOIN MyTable3#dblink1 T3 ON T3.Id2 = T2.Id
This query is very simple and fast (about 1 min, T1 contain about 1 million rows, T3 more then 10 million rows). Now I want to use MyTable4 from dblink1 for filtering selected rows data. For it, I use subquery:
SELECT T1.*,
T3.*
FROM MyTable1 T1
INNER JOIN MyTable2 T2 ON T2.Id1 = T1.Id
LEFT JOIN (SELECT Sub_T1.*
FROM MyTable3#dblink1 Sub_T1
INNER JOIN MyTable4#dblink1 Sub_T2 ON Sub_T2.Id3 = Sub_T1.Id
WHERE
Sub_T2.MyColumn1 = 'required value') T3 ON T3.Id2 = T2.Id
But this query is too slow (more then 20min). If I rewrite this query to:
SELECT T1.*,
T3.*
FROM MyTable1 T1
INNER JOIN MyTable2 T2 ON T2.Id1 = T1.Id
LEFT JOIN MyTable3#dblink1 T3 ON T3.Id2 = T2.Id
LEFT JOIN MyTable4#dblink1 T4 ON T4.Id3 = T3.Id
WHERE
T4.MyColumn1 = 'required value'
Then my query work fast again, but I donn't like result (I want to see columns of T3 as null, if WHERE return false).
How to improve my second query, for speed up it?
Does phrasing the query with parentheses solve the problem?
SELECT T1.*,
T3.*
FROM MyTable1 T1 INNER JOIN
MyTable2 T2
ON T2.Id1 = T1.Id LEFT JOIN
(MyTable3#dblink1 T3 JOIN
MyTable4#dblink1 T4
ON T4.Id3 = T3.Id AND
T4.MyColumn1 = 'required value'
)
ON T3.Id2 = T2.Id;
Or, also:
SELECT T1.*,
T3.*
FROM MyTable1 T1 INNER JOIN
MyTable2 T2
ON T2.Id1 = T1.Id LEFT JOIN
MyTable3#dblink1 T3
ON T3.Id2 = T2.Id
EXISTS (SELECT 1 FROM MyTable4#dblink1 T4 WHERE T4.Id3 = T3.Id AND T4.MyColumn1 = 'required value'
)

join with the on supplied later

I have a query in the following format
select
*
from
Table1 t1
inner join Table2 t2
inner join Table3 t3 on t2.ID = t3.ID
on t3.ID = t1.ID
What I do know:
Not providing the last on condition results in an error.
Additionally changing the first join condition from on t2.ID = t3.ID to on t1.ID = t2.ID results in an error that t1.ID could not be bound.
Obviously the above examples are arbitrary and may not actually produce a practically useful result. However, an explanation of what providing the on later is actually doing would be great.
Thanks
EDIT
I'm not trying to change the question to something that works but to understand what MSSQL is doing when I provide it.
You can use the format you specified (presuming the correct table aliases), if you use parenthesis.
Select ... -- never use Select *
From (Table1 As T1
Join Table2 As T2
On T2.ID = T1.ID)
Join Table3 As T3
On T3.ID = T1.ID
However, with equi-joins (inner joins) it really makes no difference and it is easier to read if you do not use parenthesis. However, this format is very useful with outer joins. Take the following two examples:
Example 1
Select ...
From Table1 As T1
Left Join Table2 As T2
On T2.T1_ID = T1.ID
Join Table3 As T3
On T3.T2_ID = T2.ID
Example 2
Select ...
From Table1 As T1
Left Join (Table2 As T2
Join Table3 As T3
On T3.T2_ID = T2.ID)
On T2.T1_ID = T1.ID
Suppose in this situation, that T3.T2_ID is a non-nullable foreign key to Table2. In Example1, the Inner Join to Table3 will effectively filter out rows that would have been null because the given T2.T2_ID does not exist in Table1. However, in the second example, the join between Table2 and Table3 is done before the Left Join to Table1 is processed. Thus, we'll get the same rows from Table1 and Table2 as:
Example 3
Select ...
From Table1 As T1
Left Join Table2 As T2
On T2.T1_ID = T1.ID
Assuming you meant t1 rather than t, then your query:
select
*
from
Table1 t1
inner join Table2 t2
inner join Table3 t3 on t2.ID = t3.ID
on t3.ID = t1.ID
...can be made rather more clear by the addition of the brackets it doesn't really need:
select
*
from
Table1 t1
inner join
(Table2 t2 inner join Table3 t3 on t2.ID = t3.ID) on t3.ID = t1.ID
Effectively, you're explicitly saying "join t2 to t3, then join t1 to that."
Does that help?
First off--you don't define what t is
Table1 is aliased t1
Table2 is aliased t2
Table3 is aliased t3
But there is no plain t.
Second, you are not doing a join of t1 to t2, but of t1 to t3 and then t3 to t2. That will work. If there is a relation between t1 and t2 (t1.ID=t2.ID) then that "on" statement should directly follow the inner join statement for t2:
select
*
from
Table1 t1
inner join Table3 t3 on t1.ID = t3.ID
inner join Table2 t2 on t3.ID = t2.ID
UPDATE (based on your update)
are t1.ID, t2.ID, and t3.ID all the same data type?

How do I force join inside a left join branch?

I need to LEFT join to entire t2+t3 branch, but if I can find a matching join between t1 and t2, I want to enforce the t2 and t3 join.
SELECT T1.name,T2.bob,T3.a
FROM T1
LEFT JOIN T2 ON t1.id = t2.t1_id
JOIN T3 ON t2.id = T3.t2_id
What is the syntax?
Sample data:
T1 [id,name]
1 aaa
2 bbb
3 ccc
T2 [id,t1_id,bob]
1,1,777
2,1,888
2,2,999
T3[id,t2_id,a]
1,2,'yeh'
EXPECTED RESULT:
[name] , [a] , [bob]
aaa , 'yeh' , 888
bbb , NULL , NULL
ccc , NULL , NULL
EDIT: This query returns you the result as expected from your sample data -
(Also note, this query is taken with help from Treefrog's answer below) -
SELECT t1.[name], t3.a, t2.bob
FROM T2 as t2
JOIN T3 as t3 ON t3.t2_id = t2.id
RIGHT JOIN T1 as t1 ON t1.id = t2.t1_id
My Older answer -
SELECT a
FROM T1 as t1
INNER JOIN T2 as t2 ON t1.id = t2.t1_id
LEFT JOIN T3 as t3 ON t2.id = t3.t2_id
SELECT T1.a
FROM T2
JOIN T3 ON T3.t2_id = T2.id
RIGHT JOIN T1 ON T1.id = T2.t1_id
Both of these will give you your result. Not sure which would perform better.
NESTED STATEMENT:
SELECT [name], NULL AS [a], NULL AS [bob]
FROM t1
LEFT OUTER JOIN t2 ON t1.id = t2.t1_id
LEFT OUTER JOIN t3 ON t2.id = t3.t2_id
WHERE t3.t2_id IS NULL
AND (SELECT COUNT(*) FROM t1 AS t1b LEFT OUTER JOIN t2 AS t2b ON t1b.id = t2b.t1_id LEFT OUTER JOIN t3 AS t3b ON t2b.id = t3b.t2_id WHERE t1.id = t1b.id AND t3b.a IS NOT NULL) = 0
UNION
SELECT [name], [a], [bob]
FROM t1
LEFT OUTER JOIN t2 ON t1.id = t2.t1_id
LEFT OUTER JOIN t3 ON t2.id = t3.t2_id
WHERE t3.t2_id IS NOT NULL
ORDER BY t1.name
TEMPORARY TABLE:
CREATE TABLE #tmp_Rslt([name] varchar(50), [a] varchar(50), [bob] varchar(50))
--select matches
INSERT INTO #tmp_Rslt
SELECT [name], [a], [bob]
FROM t1
LEFT OUTER JOIN t2 ON t1.id = t2.t1_id
LEFT OUTER JOIN t3 ON t2.id = t3.t2_id
WHERE t3.t2_id IS NOT NULL
ORDER BY t1.name
--select t1's that didn't have matches
INSERT INTO #tmp_Rslt
SELECT [name], NULL AS [a], NULL AS [bob]
FROM t1
LEFT OUTER JOIN t2 ON t1.id = t2.t1_id
LEFT OUTER JOIN t3 ON t2.id = t3.t2_id
WHERE t3.t2_id IS NULL
AND t1.[name] NOT IN (SELECT DISTINCT [name] FROM #tmp_Rslt)
SELECT *
FROM #tmp_Rslt
--cleanup.
DROP TABLE #tmp_Rslt
This should work in MySQL
SELECT * FROM T1
LEFT JOIN (T2
INNER JOIN T3 ON T2.id=T3.t2_id
) ON T1.id= T2.t1_id