Reputation: 37
I have a query which needs to retrieve data from multiple tables. For two of these tables, the data is retrieved by an outer apply
, as it is necessary to query a time range for the data.
SELECT a.DATA, b1.DATA, c1.DATA
FROM TABLE_A a
OUTER APPLY
(SELECT TOP 1 b.[DATA]
FROM TABLE_B b
WHERE b.TIME_START <= a.TIME_START
) AS b1
OUTER APPLY
(SELECT TOP 1 c.[DATA]
FROM TABLE_C c
WHERE c.TIME_START <= a.TIME_START
AND c.TIME_STOP >= a.TIME_START
) AS c1
My problem is that TABLE_C
is a very big table and querying this table takes some time, but I would only need to query this table if the result from TABLE_B
is null. TABLE_B
is rather small compared to TABLE_C
.
For example, this is a valid result of the query:
[a.DATA] [b.DATA] [c.DATA]
1 VALUE_A VALUE_2 NULL
2 VALUE_B NULL VALUE_3
Is there a way to make the outer apply to TABLE_C
conditional to the result of TABLE_B
for each row, as in the above example to only execute for line 2?
Upvotes: 3
Views: 2272
Reputation: 35780
Something like this:
SELECT a.DATA ,
b1.DATA ,
c1.DATA
FROM TABLE_A a
OUTER APPLY ( SELECT TOP 1
b.[DATA]
FROM TABLE_B b
WHERE b.TIME_START <= a.TIME_START
) AS b1
OUTER APPLY ( SELECT CASE WHEN b1.[DATA] IS NULL
THEN ( SELECT TOP 1
c.[DATA]
FROM TABLE_C c
WHERE c.TIME_START <= a.TIME_START
AND c.TIME_STOP >= a.TIME_START
)
ELSE NULL
END AS DATA
) AS c1
Or:
SELECT a.DATA ,
b1.DATA ,
c1.DATA
FROM TABLE_A a
OUTER APPLY ( SELECT TOP 1
b.[DATA]
FROM TABLE_B b
WHERE b.TIME_START <= a.TIME_START
) AS b1
OUTER APPLY ( SELECT TOP 1
c.[DATA]
FROM TABLE_C c
WHERE c.TIME_START <= a.TIME_START
AND c.TIME_STOP >= a.TIME_START AND b1.[DATA] IS NULL
) AS c1
Upvotes: 2
Reputation: 5745
SELECT a.DATA, b1.DATA, c1.DATA
FROM TABLE_A a
OUTER APPLY
(SELECT TOP 1 b.[DATA]
FROM TABLE_B b
WHERE b.TIME_START <= a.TIME_START
) AS b1
OUTER APPLY
(SELECT TOP 1 c.[DATA]
FROM TABLE_C c
WHERE c.TIME_START <= a.TIME_START
AND c.TIME_STOP >= a.TIME_START
AND b1.data IS NULL
) AS c1
But I do not know what optimizer will do in that case. Will it take all data from C and after that remove all the records with B. However you can also try to duplicate the query:
SELECT a.DATA, b1.DATA, c1.DATA
FROM TABLE_A a
OUTER APPLY
(SELECT TOP 1 b.[DATA]
FROM TABLE_B b
WHERE b.TIME_START <= a.TIME_START
) AS b1
OUTER APPLY
(SELECT TOP 1 c.[DATA]
FROM TABLE_C c
WHERE c.TIME_START <= a.TIME_START
AND c.TIME_STOP >= a.TIME_START
AND NOT EXISTS (
SELECT * FROM TABLE_B b WHERE b.TIME_START <= a.TIME_START
)
) AS c1
Upvotes: 1