Query optimization in SQL Server - sql

SELECT
T2.Entity1Id, T1.Entity1Id
FROM
T1
FULL OUTER JOIN
T2 ON T1.c2 = T2.c2 AND T1.c1 = T2.c1 AND T1.c3 = 1
WHERE
((T1.c1 = 123 ) OR (T2.c1 = 123))
AND (T1.c3 = 1 OR T1.c3 IS NULL)
Above query is taking 12 seconds in SQL Server 2014, any idea to tune the query? There are indexes on C1,C2,C3 columns.
Observation: in the above query, when I remove a condition from OR (i.e.
SELECT
T2.Entity1Id, T1.Entity1Id
FROM
T1
FULL OUTER JOIN
T2 ON T1.c2 = T2.c2 AND T1.c1 = T2.c1 AND T1.c3 = 1
WHERE
(T1.c1 = 123) AND (T1.c3 = 1 OR T1.c3 IS NULL)
then it's returning results in 0 seconds.
Each table has around 500'000 records.

First, the final condition (T1.c3 = 1 OR T1.c3 IS NULL) is redundant. Given the join condition, these are the only possible values. So, the query is:
SELECT T2.Entity1Id, T1.Entity1Id
FROM T1 FULL OUTER JOIN
T2
ON T1.c2 = T2.c2 AND T1.c1 = T2.c1 AND T1.c3 = 1
WHERE (T1.c1 = 123 ) OR (T2.c1 = 123)
If this doesn't have good performance, consider breaking this into two queries:
SELECT T2.Entity1Id, T1.Entity1Id
FROM T1 LEFT JOIN
T2
ON T1.c2 = T2.c2 AND T1.c1 = T2.c1 AND T1.c3 = 1
WHERE T1.c1 = 123
UNION
SELECT T2.Entity1Id, T1.Entity1Id
FROM T2 LEFT JOIN
T1
ON T1.c2 = T2.c2 AND T1.c1 = T2.c1 AND T1.c3 = 1
WHERE T2.c1 = 123
Sometimes, the optimization of the separate subqueries is much better than the optimization for the full outer join.

Related

Conversion of Oracle join to Ansi join

I need to convert the following Oracle SQL to ANSI SQL.
Select t1.c1, t2.c2, t1.c3 from t1, t2 where
T1.c1=t2.c1(+) and
T1.c2=t2.c2(+) and
T1.c3=t2.c3 and
T1.c4=t2.c4 and
T1.c1='1'
This would be outer join if all columns in t2 had the (+) modifier.
That would look like:
Select t1.c1, t2.c2, t1.c3
from t1 left join
t2
on T1.c1 = t2.c1 and T1.c2 = t2.c2 and
T1.c3 = t2.c3 and T1.c4 = t2.c4
where T1.c1 = '1';
However, your version is an inner join, because some of the columns do need to match -- so there needs to be a matching row in the second table.
So, the real equivalent is just:
Select t1.c1, t2.c2, t1.c3
from t1 join
t2
on T1.c1 = t2.c1 and T1.c2 = t2.c2 and
T1.c3 = t2.c3 and T1.c4 = t2.c4
where T1.c1 = '1';
And the (+) is not relevant.

Subquery in Inner join - Multi-part identifer could not be bound

I have the following query and I am getting a multi-part identifier could not be bound exception. I realize why and my next thought was to use a CROSS APPLY, which didn't work. What I really need to do is join that subquery to make sure I get the most recent entry for a particular column.
Unfortunately, I've run out of ideas... How do I accomplish this query?
SELECT t1.*
FROM dbo.Table1 t1 (nolock)
INNER JOIN
(
SELECT TOP 1 t2_s.c1, t2_s.c2, t2_s.c4
FROM dbo.Table2 t2_s
WHERE t2_s.c1 = t1.c1
ORDER BY t2_s.dateStamped DESC
) t2
on t2.c1 = t1.c1
INNER JOIN dbo.Table3 t3
on t3.c1 = t2.c2 and t3.c2 = 1
WHERE t1.c2 = 'xxx'
Assuming you are using SQL Server, then CROSS APPLY should do what you want:
SELECT t1.*
FROM dbo.Table1 t1 (nolock) CROSS APPLY
(SELECT TOP 1 t2_s.c1, t2_s.c2, t2_s.c4
FROM dbo.Table2 t2_s
WHERE t2_s.c1 = t1.c1
ORDER BY t2_s.dateStamped DESC
) t2 INNER JOIN
dbo.Table3 t3
on t3.c1 = t2.c2 and t3.c2 = 1
WHERE t1.c2 = 'xxx';

Adding a variable to a join table

I'm struggling to figure out how I can add a convenience data column to a join table to use for evaluation.
Sorry if the terminology is incorrect, I'm a bit of an SQL newbie.
For this query structure:
SELECT t1.id
FROM
table1 t1
INNER JOIN
table2 t2 ON t1.c2 = t2.c1
WHERE
t1.c5=5;
...I would like to add a column in the join table that is calculated using a function of a few of t1s columns. For example, the sum of t1.x, t1.y, t1.z in a variable called score that can then be referenced in the WHERE clause.
The reason behind wanting to do this is it will be referenced multiple times and will reduce verbosity and help readability.
I presume it will look something like:
SELECT t1.id
FROM
table1 t1
INNER JOIN
table2 t2 ON t1.c2 = t2.c1
-- function(t1.x, t1.y, t1.z) as score
WHERE
t1.c5=5;
--AND score ...
Using PostgreSQL 9.3
If the score is calculated from the t1 columns, then use a subquery on t1:
SELECT t1.id
FROM (select t1.*, function(t1.x, t1.y, t1.z) as score
from table1 t1
) t1 INNER JOIN
table2 t2
ON t1.c2 = t2.c1
WHERE t1.c5 = 5 AND
t1.score . . .
A good option would be to use the having clause.
Select t1.id, SUM(t1.x + t1.y + t1.z)
FROM table1 t1 inner join table2 t2 on t1.c2 = t2.c1
WHERE t1.c5 = 5
GROUP BY t1.id
Having SUM(t1.x + t1.y + t1.z) = ...
Or, you could do a sub-query in the from clause. The below code makes some assumptions on structure.
SELECT t1.id
FROM
(Select SUM(t1.x + t1.y + t1.z) as score, t1.c5, t1.c2, t1.id
FROM table1 t1
GROUP BY t1.id
) t1
INNER JOIN table2 t2 on t1.c2 = t2.c1
WHERE
t1.c5=5
And t1.score = ...

SQL SERVER 2005 CASE WHEN THEN END

I am running following query..
Select T1.* from T1
LEFT JOIN T2 ON T1.C1 = T2.C1
LEFT JOIN T3 ON T2.C3 = T3.C3
ORDER BY Case When T1.C1 = 'ABC' THEN 'XYZ' END AS COMMENTS
Its giving me Syntax error near AS. Unable to figure out the error.
You don't need the AS alias when using case in an order by
Select T1.* from T1
LEFT JOIN T2 ON T1.C1 = T2.C1
LEFT JOIN T3 ON T2.C3 = T3.C3
ORDER BY Case When T1.C1 = 'ABC' THEN 'XYZ' END
It's because you are trying to assign an alias to the ORDER BY clause - this is not allowed and I'm not sure what you want to achieve here?
You either need:
Select T1.* from T1
LEFT JOIN T2 ON T1.C1 = T2.C1
LEFT JOIN T3 ON T2.C3 = T3.C3
ORDER BY Case When T1.C1 = 'ABC' THEN 'XYZ' END
Or, if you want that CASE value to be returned in the SELECT as well, then you need:
Select T1.*, Case When T1.C1 = 'ABC' THEN 'XYZ' END AS COMMENTS
from T1
LEFT JOIN T2 ON T1.C1 = T2.C1
LEFT JOIN T3 ON T2.C3 = T3.C3
ORDER BY Case When T1.C1 = 'ABC' THEN 'XYZ' END
Also, again not sure of intention here so it depends, but you may need an ELSE on that CASE...
e.g.
ORDER BY CASE WHEN T1.C1 = 'ABC' THEN 'XYZ' ELSE T1.C1 END

Joining 3 tables to get only two rows

I have three table I need to query table 1,2 and 3 and select C1 from Table 1 and C2 from table 2 and 3 respectively so that it would give result. Is there any way of getting this?
Yes:
select t1.c1, coalesce(t2.c2, t3.c2) c2
from Table1 t1
left join Table2 t2 on t1.c1 = t2.c1
left join Table3 t3 on t1.c1 = t3.c1
Try the following:
SELECT T1.C1, T2.C2
FROM T1
INNER JOIN T1.C1 = T2.C1
UNION ALL
SELECT T1.C1, T3.C2
FROM T1
INNER JOIN T1.C1 = T3.C1