在存储过程中重用SELECT查询的结果

时间:2016-02-13 08:47:37

标签: sql sql-server tsql stored-procedures

这可能是一个非常简单的问题,但我试图搜索答案却被谷歌找到了答案,这些答案显示了如何通过制作存储过程来重用查询。我想在存储过程中重用查询的结果。

这是一个简洁的例子,我已经删除了NOCOUNTXACT_ABORTTRANSACTIONTRY以及大部分逻辑。

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

重复使用重复嵌套SELECT的结果而不是两次执行的语法是什么?

3 个答案:

答案 0 :(得分:3)

您可以将SELECT的结果INSERT到临时表或表变量中,但它并不自动意味着整体性能会更好。你需要测量它。

临时表

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

表格变量

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

答案 1 :(得分:1)

您可以声明一个表变量来存储select的结果,然后只是查询它。

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

答案 2 :(得分:1)

如果子查询快速而简单 - 无需更改任何内容。在第一次查询之后,项目的数据位于缓存中(如果不是),则获取锁定。如果子查询缓慢而复杂 - 将其存储到表变量中并通过重复使用问题中列出的相同子查询

如果您的问题与性能无关,并且您要注意复制粘贴:没有复制粘贴。有相同的逻辑,类似的结构和引用 - 是的,你将拥有几乎相同的查询源代码。

一般来说,它不一样。除非您在SERIALIZABLE隔离级别下运行,否则可以在第一个查询之后从Items表中删除或插入某些行。在第一次删除期间,第一次和第二次删除语句之间可能发生许多不同的事每个delete语句也需要它自己的执行计划 - 因此无论如何必须将所有关于受影响的表和连接的信息提供给SERVER。您需要再次使用相同的源进行过滤 - 是的,您再次为子查询提供相同的源。部分代码没有“两次”或“重复使用”。通过复杂查询收集的数据 - 是的,它可以通过临时表/表变量重复使用(不运行相同的复杂查询 - 通过从准备好的源简单查询)之前。