是否可以在执行语句

时间:2016-05-18 10:20:51

标签: sql-server tsql stored-procedures

当我在存储过程中工作以避免服务器端的sting查询时,我想出了一个问题“为什么我在执行语句之前不验证传入的数据?”在我进一步开展工作之前,我决定在Stack Overflow中提出一个问题,因为有很高的专业成员。

这是工作的一个例子

TTable的

CREATE TABLE [dbo].[Ttable] (
    [TtableId]         INT            IDENTITY (1, 1) NOT NULL,
    [Ttablecol]        NVARCHAR (MAX) NOT NULL,
    [IsTtableIsActive] BIT            NOT NULL,
    PRIMARY KEY CLUSTERED ([TtableId] ASC)
);

示例1

CREATE PROCEDURE [dbo].[spAddToTtable]
    @param NVARCHAR(MAX) = ''
AS
BEGIN
    IF(NOT EXISTS 
      (SELECT NULL 
       FROM   Ttable
       WHERE  Ttablecol = @param))
    BEGIN
    INSERT 
    INTO    Ttable(Ttablecol,IsTtableIsActive)
    VALUES  (@param,1)
    SELECT SCOPE_IDENTITY() AS INT 
    END
    ELSE
    BEGIN
        IF(EXISTS 
          (SELECT NULL 
           FROM   Ttable
           WHERE  Ttablecol = @param 
             AND  IsTtableIsActive = 0 ))
        BEGIN
            SELECT -2 AS INT 
        END
        ELSE
        BEGIN
            SELECT -1 AS INT
        END
    END
END

示例2

CREATE PROCEDURE [dbo].[spInActiveTtable]
@param INT = 0
AS
BEGIN
    IF(EXISTS 
      (SELECT NULL 
       FROM   Ttable
       WHERE  IsTtableIsActive = 1))
    BEGIN
    UPDATE Ttable
    SET IsTtableIsActive = 0
    WHERE TtableId = @param
    SELECT SCOPE_IDENTITY() AS INT 
    END
    ELSE
    BEGIN
        IF(EXISTS 
          (SELECT NULL 
           FROM   Ttable
           WHERE  Ttablecol = @param 
             AND  IsTtableIsActive = 0 ))
        BEGIN
            SELECT -2 AS INT 
        END
        ELSE
        BEGIN
            SELECT -1 AS INT
        END
    END
END

示例3

CREATE PROCEDURE [dbo].[spReActiveTtable]
@param INT = 0
AS
BEGIN
    IF(EXISTS 
      (SELECT NULL 
       FROM   Ttable
       WHERE  IsTtableIsActive = 0))
    BEGIN
    UPDATE Ttable
    SET IsTtableIsActive = 1
    WHERE TtableId = @param
    SELECT SCOPE_IDENTITY() AS INT 
    END
    ELSE
    BEGIN
        IF(EXISTS 
          (SELECT NULL 
           FROM   Ttable
           WHERE  Ttablecol = @param 
             AND  IsTtableIsActive = 1 ))
        BEGIN
            SELECT -3 AS INT 
        END
        ELSE
        BEGIN
            SELECT -1 AS INT
        END
    END
END

例4

CREATE PROCEDURE [dbo].[spModifyTtable]
@param INT = 0,
@param2 nvarchar(max) = ''
AS
BEGIN
    IF((SELECT  Ttablecol 
          FROM  Ttable
          WHERE TtableId = @param) = @param2)
          BEGIN 
          SELECT -5 AS INT 
          END 
    ELSE 
    BEGIN
    UPDATE  Ttable
    SET     Ttablecol = @param2
    SELECT -6 AS INT 
    END 
END

我的做法是否正确?

非常感谢您的帮助,我希望我的问题很有用

2 个答案:

答案 0 :(得分:2)

你的问题的答案是讨厌的“它取决于”。

真正的问题是你想要实现的目标是什么?如果您只是尝试强制执行数据完整性,我会尽可能坚持使用唯一性约束,外键等,否则您只是在做SQL Server可以为您做的工作(并且更有效)。

如果您的调用应用程序需要根据记录的存在执行不同的业务逻辑,或者您无法通过标准方法强制执行数据完整性约束,那么我认为这种方法很好。但是,请确保执行这些额外检查具有实际价值,因为您现在正在为查询添加额外的复杂性和性能开销。随着数据库的不断增长,您可能会发现这些额外的检查会大大减慢您的速度。

您的第一个示例是充分利用存在性检查,因为您无法在NVARCHAR(MAX)列上添加唯一性约束。需要注意的是,现在您正在对未编入索引的可能非常大的列执行搜索。根据您的表增长的大小,这可能会随着时间的推移变成非常昂贵的查询。如果你的桌子保持相对较小,那么这就不那么重要了。

我对你的另一个例子不太热心。至少你总是执行2选择,从我所看到的,实际上没有帮助强制执行任何约束或提供您可能通过其他方式获得的任何附加信息。

让我们以第二个查询为例,您的存在检查将命中您的IsTtableIsActive列,该列未编入索引,这意味着您无法有效利用ID列上的聚簇索引。此外,由于IsTtableIsActive不允许空值,因此您永远不会遇到第3个if语句。你的第二个例子可以写成如下,并给出相同的结果:

    CREATE PROCEDURE [dbo].[spInActiveTtable]
    @param INT = 0
    AS
    BEGIN

        DECLARE @affectedRows INT = 0;
        DECLARE @recordID INT = -1;

        UPDATE Ttable
        SET IsTtableIsActive = 0
        WHERE TtableId = @param AND IsTtableIsActive = 1

        SET @recordID = SCOPE_IDENTITY();
        SET @affectedRows = @@ROWCOUNT;

        IF @affectedRows > 0
            SET @recordID = -1;

        SELECT @recordID;

    END

上述查询只是在update语句本身的were子句中检查IsTtableIsActive = 1。您的聚集索引现在正在使用,SQL Server不必对您的表执行2次扫描。如果@@ ROWCOUNT返回0,那么我们知道记录的条件,我们尝试更新不符合。

答案 1 :(得分:0)

我有两个答案选项

第一个选项

CREATE PROCEDURE [dbo].[spInActiveTtable]

@param INT = 0

AS
BEGIN

    -- -1 ROW WAS AFFECTED
    -- -2 ROW WAS NOT AFFECTED 

        DECLARE @recordID INT = -1;

        UPDATE  Ttable
        SET     IsTtableIsActive = 0
        WHERE   TtableId         = @param 
          AND   IsTtableIsActive = 1

        IF (@@ROWCOUNT > 0)
        BEGIN
            SET @recordID = -2;
        END

        SELECT @recordID AS INT

END

第二个选项

CREATE PROCEDURE [dbo].[spInActiveTtable]

@param INT = 0

AS
BEGIN

    -- -1 ROW WAS AFFECTED
    -- @param ROW WAS NOT AFFECTED 

        DECLARE @recordID INT = -1;

        UPDATE  Ttable
        SET     IsTtableIsActive = 0
        WHERE   TtableId         = @param 
          AND   IsTtableIsActive = 1

        IF (@@ROWCOUNT > 0)
        BEGIN
            SET @recordID = @param;
        END

        SELECT @recordID AS INT

END