Reputation: 17527
This is probably a very simple question, but my attempts to search for an answer are thwarted by Google finding answers showing how to reuse a query by making a stored procedure instead. I want to reuse the results of a query inside a stored procedure.
Here's a cut-down example where I've chopped out NOCOUNT
, XACT_ABORT
, TRANSACTION
, TRY
, and much of the logic.
CREATE PROCEDURE Do_Something
@userId UNIQUEIDENTIFIER
AS
BEGIN
DELETE FROM LikedItems
WHERE likedItemId IN
(
SELECT Items.id FROM Items
WHERE Items.userId = @userId
)
DELETE FROM FollowedItems
WHERE followedItemId IN
(
SELECT Items.id FROM Items
WHERE Items.userId = @userId
)
END
What is the syntax to reuse the results of the duplicated nested SELECT
rather than doing it twice?
Upvotes: 4
Views: 3110
Reputation: 9299
If the subquery is fast and simple - no need to change anything. Item's data is in the cache (if it was not) after the first query, locks are obtained. If the subquery is slow and complicated - store it into a table variable and reuse by the same subquery as listed in the question.
If your question is not related to performance and you are beware of copy-paste: there is no copy-paste. There is the same logic, similar structure and references - yes, you will have almost the same query source code.
In general, it is not the same. Some rows could be deleted from or inserted into Items table after the first query unless your are running under SERIALIZABLE isolation level. Many different things could happen during first delete, between first and second delete statements. Each delete statement also requires it's own execution plan - thus all the information about tables affected and joins must be provided to SERVER anyway. You need to filter by the same source again - yes, you provide subquery with the same source again. There is no "twice" or "reuse" of a partial code. Data collected by a complicated query - yes, it can be reused (without running the same complicated query - by simple querying from prepared source) via temp tables/table variables as mentioned before.
Upvotes: 1
Reputation: 32685
You can INSERT result of the SELECT into a temporary table or table variable, but it doesn't automatically mean that the overall performance would be better. You need to measure it.
Temp Table
CREATE PROCEDURE Do_Something
@userId UNIQUEIDENTIFIER
AS
BEGIN
CREATE TABLE #Temp(id int);
INSERT INTO #Temp(id)
SELECT Items.id
FROM Items
WHERE Items.userId = @userId;
DELETE FROM LikedItems
WHERE likedItemId IN
(
SELECT id FROM #Temp
)
DELETE FROM FollowedItems
WHERE followedItemId IN
(
SELECT id FROM #Temp
)
DROP TABLE #Temp;
END
Table variable
CREATE PROCEDURE Do_Something
@userId UNIQUEIDENTIFIER
AS
BEGIN
DECLARE @Temp TABLE(id int);
INSERT INTO @Temp(id)
SELECT Items.id
FROM Items
WHERE Items.userId = @userId;
DELETE FROM LikedItems
WHERE likedItemId IN
(
SELECT id FROM @Temp
)
DELETE FROM FollowedItems
WHERE followedItemId IN
(
SELECT id FROM @Temp
)
END
Upvotes: 3
Reputation: 8877
You can declare a table variable to store the results of the select and then simply query that.
CREATE PROCEDURE Do_Something
@userId UNIQUEIDENTIFIER
AS
BEGIN
DECLARE @TempItems TABLE (id int)
INSERT INTO @TempItems
SELECT Items.id FROM Items
WHERE Items.userId = @userId
DELETE FROM LikedItems
WHERE likedItemId IN
(
SELECT id FROM @TempItems
)
DELETE FROM FollowedItems
WHERE followedItemId IN
(
SELECT id FROM @TempItems
)
END
Upvotes: 1