当我在存储过程中工作以避免服务器端的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
我的做法是否正确?
非常感谢您的帮助,我希望我的问题很有用
答案 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