I have two queries:
1)
select a.*
,b.*
,c.*
into final_table
from table_a as a
left join table_b as b
on a.id_1 = b.id_1
left join table_c as c
on a.id_2 = c.id_2;
2)
select a.*
,b.*
into #temp_1
from table_a as a
left join table_b as b
on a.id_1 = b.id_1;
select t.*
,c.*
into final_table
from #temp_1 as t
left join table_c as c
on t.id_2 = c.id_2;
I observe that second query runs significantly faster on SQL Server 2012. Is is by accident, or there is a good reason for it?
Related
I am trying to join two tables on two different columns and I was wondering if following two techniques are equivalent, if yes which one is better performance wise?
JOIN with OR (Conditional JOIN)
SELECT *
FROM table1
JOIN TABLE2 ON table1.value = table2.HighValue
OR table1.value = table2.LowValue
Using self Join
SELECT *
FROM TABLE1
JOIN table2 t2 ON table1.value = t2.HighValue
JOIN table2 t3 ON table1.value = t3.LowValue
The two queries are not equivalent, the first is equivalent to
SELECT *
FROM table1
JOIN TABLE2 ON table1.value = table2.HighValue
UNION
SELECT *
FROM table1
JOIN TABLE2 ON table1.value = table2.LowValue
I have 3 Tables:
TableA(IDRem, IDPed, IDOP)
TableB(IDOP, IDPed)
TableC(IDPed, InvoiceDate)
I need a select to JOIN the records of TableA and TableC, but there are two possible conditions:
IF IDPed on TableA IS NOT NULL, then join directly to TableC by IDPed
ID IDPed on TableA IS NULL, then join to TableB by IDOp, and then join TableB to TableC by IDPed
So far i try this:
SELECT
TableA.*
,(CASE WHEN TableC.InvoiceDate IS NULL
THEN TableC2.InvoiceDate
ELSE TableC.InvoiceDate
END) AS InvoiceDate
FROM
TableA
LEFT JOIN TableC on TableA.IDPed = TableC.IDPed
LEFT JOIN TableB on TableB.IDOp = TableA.IDOp
INNER JOIN TableC as TableC2 on TableC2.IDPed = TableB.IDPed
The problem with this is that every field o tableA I want to include in the select I need to do a case...when to determine if the origin is tableA or TableA2.
Is there a better way of doing this? Thanks!
For complex joins you are better served in TSQL using cross apply:
When should I use Cross Apply over Inner Join?
select IDRem, IDPed, IDOP from TableA a
cross apply(
select IDOP, IDPed from TableB binner
where a.IDop = binner.IDop
) b
cross apply(
select IDPed, InvoiceDate cinner
where b.IDPed = cinner.IDPed
) c
where ...
Strictly psuedo-code but should give you a start.
You could try doing both JOINs and use UNION ALL
Edit: As pointed out in the comment by Vladimir Baranov, there's no need to check if a.IdPed IS NULL on the first SELECT since if it is, the JOIN would return no rows.
SELECT
a.*,
c.InvoiceDate
FROM TableA a
INNER JOIN TableC c ON c.IdPed = a.IdPed
UNION ALL
SELECT
a.*,
c.InvoiceDate
FROM TableA a
INNER JOIN TableB b ON b.IdOp = a.IdOP
INNER JOIN TableC c ON c.IdPed = b.IdPed
WHERE a.IdPed IS NULL
The following is my CTE:
;WITH CTE AS
(SELECT O.*, E.Num, E.Amount
FROM OData O
INNER JOIN Equip E
ON O.Name = E.Name)
SELECT * FROM CTE -- gives results I want to join to
The following is the query that I want to SELECT from (and only use this SELECT statement for my query results:
SELECT
MU.Type
,MU.Num
,MU.MTBUR
,MF.MTBF
,MU.Hours
,MF.Hours
FROM
MUType_Stage MU
INNER JOIN
MFType_Stage MF
ON
MU.Type = MF.Type
AND
MU.Num = MF.Num
-- Need do JOIN to CTE right here
INNER JOIN
Status_STAGE S
ON
MU.Nu = S.Part
LEFT OUTER JOIN
RCN N
ON
N.Name = R.Part
LEFT OUTER JOIN
Repair RR
ON
R.ACSS_Name = RR.Name
So basically I need to JOIN to the CTE inside the SELECT query in which I want the results.
OR ALTERNATIVELY Uses this select statement to join to the CTE but only what the selected columns from the second select statement
Try this syntax
WITH CTE
AS (SELECT O.*,
E.Num,
E.Amount
FROM OData O
INNER JOIN Equip E
ON O.Name = E.Name)
SELECT MU.Type,
MU.Num,
MU.MTBUR,
MF.MTBF,
MU.Hours,
MF.Hours
FROM MUType_Stage MU
INNER JOIN MFByACType_Stage MF
ON MU.Type = MF.Type
AND MU.Num = MF.Num
INNER JOIN CTE C --- JOIN HERE as like other tables
ON C.Num = MF.Num
INNER JOIN Status_STAGE S
ON MU.Nu = S.Part
LEFT OUTER JOIN RCN N
ON N.Name = R.Part
LEFT OUTER JOIN Repair RR
ON R.ACSS_Name = RR.Name
Is there a way to have an if statement determine whether a join is necessary or not?
I need this because there are multiple foreign keys in the data I querying. if any of the foreign keys are null I need to change the SQL statement. I would like to write one statement that can be aware of any null values.
This is what I would like to do...
select a.*,b.* from table1 a inner join table2 b on a.id = b.id
if a.InspectorID is not null
{inner join table3 c on a.InspectionID = c.id}
else do nothing...
try this out...
select a.*,b.* from table1 a inner join table2 b on a.id = b.id
left join table3 c on a.InspectionID = c.id
where a.InspectorID is null or a.InspectionID = c.id
I am not sure, if you can conditionally join tables, but the "if" statement in t-sql is calles
case.
What about using union
select a.*,b.*
from table1 a
inner join table2 b on a.id = b.id
inner join table3 c on a.InspectionID = c.id
union all
select a.*,b.*
from table1 a
inner join table2 b on a.id = b.id
where a.InspectionID is null
If I understand correctly, you could use:
select a.*,b.*,c.fields
from table1 a inner join table2 b on a.id = b.id
left join table3 c on a.InspectionID = c.id
where a.InspectionID IS NOT NULL
Use dynamic sql. For detail about dynamic sql go through:
http://exacthelp.blogspot.in/2013/02/writing-dynamic-sql-queries-in-sql.html
I would like to join several times with the same table function for different input variables in the same query. But this turns in my case out to be much slower than using table variables and selecting from the table functions separately.
How can I avoid table variables and still have a fast query?
For example, we have a SQL query like
SELECT P.ProjectName, A.Number, B.Number
FROM Project AS P
LEFT JOIN dbo.fn_ProjectNumber(#dateA) AS A
ON P.ProjectID = A.ProjectID
LEFT JOIN dbo.fn_ProjectNumber(#dateB) AS B
ON P.ProjectID = B.ProjectID
but it is much slower than selecting from the functions separately into variables and then joining later, for example:
INSERT INTO #tempA
SELECT P.ProjectID, A.Number
FROM Project AS P
LEFT JOIN dbo.fn_ProjectNumber(#dateA) AS A
ON P.ProjectID = A.ProjectID
INSERT INTO #tempB
SELECT P.ProjectID, B.Number
FROM Project AS P
LEFT JOIN dbo.fn_ProjectNumber(#dateB) AS B
ON P.ProjectID = B.ProjectID
SELECT P.ProjectName, A.Number, B.Number
FROM Project AS P
LEFT JOIN #tempA AS A
ON P.ProjectID = A.ProjectID
LEFT JOIN #tempA AS B
ON P.ProjectID = B.ProjectID
What could be the cause of this? Is there a way I can get a fast query and avoid table variables?
More details:
This is only an example similar to what I'm doing, but the function fn_ProjectNumber(#date datetime) would contain something like joins between four tables...
Try fixing the join, you refer to the wrong alias in the second LEFT JOIN:
ORIGINAL:
SELECT P.ProjectName, A.Number, B.Number
FROM Project AS P
LEFT JOIN dbo.fn_ProjectNumber(#dateA) AS A
ON P.ProjectID = A.ProjectID
LEFT JOIN dbo.fn_ProjectNumber(#dateB) AS B
ON P.ProjectID = A.ProjectID
FIXED:
SELECT P.ProjectName, A.Number, B.Number
FROM Project AS P
LEFT JOIN dbo.fn_ProjectNumber(#dateA) AS A
ON P.ProjectID = A.ProjectID
LEFT JOIN dbo.fn_ProjectNumber(#dateB) AS B
ON P.ProjectID = B.ProjectID --<<<<<
Is there any particular reason you're trying to avoid table variables? They can be a good optimisation technique and don't leave any temp objects to clean up.
Anyway, if you don't want to do it that way you could always try
SELECT
P.ProjectID, A.Number, B.Number
FROM
Project AS P
LEFT JOIN
(SELECT P.ProjectID, A.Number
FROM Project AS P
LEFT JOIN dbo.fn_ProjectNumber(#dateA) AS A
ON P.ProjectID = A.ProjectID
) AS A
ON P.ProjectID = A.ProjectID
LEFT JOIN
(SELECT P.ProjectID, B.Number
FROM Project AS P
LEFT JOIN dbo.fn_ProjectNumber(#dateB) AS B
ON P.ProjectID = B.ProjectID
) AS B
ON P.ProjectID = B.ProjectID
The joins are slow because, in your example query, you are calling each function once for each row in table Project. It's faster with the temp tables because you're only calling the function once.
One way to avoid temp tables would be to use CTEs (common table expressions--they're not just for recursion--available in SQL 2005 and up.). The general syntax would be something like:
WITH cteTempName (<list of columns>)
as (<your table function call>)
SELECT <your query here, with "cteTempName" appearing as just another table to select from>
Maybe the joins are slower because you haven't defined relations between the tables that are joined together?
I don't know much about performance of queries in SQL Server, but defining the relations will improve the performance of joins.