SQL 默认值 - 最佳实践?
Posted
技术标签:
【中文标题】SQL 默认值 - 最佳实践?【英文标题】:SQL defaults - best practice? 【发布时间】:2011-07-11 13:48:32 【问题描述】:对于具有默认约束的表,在 CREATE 和 UPDATE 存储过程中最好的做法是什么?
当我为表创建新列时,我尝试设置一个适当的默认值(默认约束)。
例子:
CREATE TABLE Orders
(
O_ID INT NOT NULL
,State INT DEFAULT 0 -- 0 => Not Verified, 1 => Verified, 2 => Processing ....
,P_ID INT
,OrderDate DATE DEFAULT GETDATE()
)
在这个表的 CREATE 和 UPDATE 存储过程中最好的做法是什么? 使用与约束中相同的默认值?
CREATE PROCEDURE UpdateOrder
(
@O_ID INT
,@State INT = 0
,@P_ID INT
,@OrderDate DATE
)
AS
UPDATE
Orders
SET
State = @State
,P_ID = @PID
,OrderDate = @OrderDate
WHERE
O_ID = @O_ID
【问题讨论】:
使用
按钮格式化代码示例 a) 比在需要换行符的地方插入大量手动 更容易,并且 b) 意味着代码获得了不错的语法突出显示。
很可能,State
列应该是 tinyint 而不是 4 字节 int。
感谢 Damien_The_Unbeliever 帮助我格式化代码。这是我的第一篇文章,所以我不太了解速度。我同意你的观点,KM 认为 TINYINT
将是 State
列的更好的数据类型选择。
【参考方案1】:
这有点重复,因为它已经在表格中默认了。
另一方面,它允许您的参数是可选的。我会说您的选择是将它们默认为与表格相同(如您所建议的那样),或者将它们默认为 null 并且表格将填充默认值。第二种方式重复性较低,容易出错。
【讨论】:
【参考方案2】:如果您希望在 UPDATE 期间更新 OrderDate,则需要将其包含在 UPDATE 语句中并使用 getdate() 代替 @OrderDate
UPDATE
Orders
SET
State = @State ,
P_ID = @PID ,
OrderDate = getdate()
WHERE O_ID = @O_ID
【讨论】:
此特定语句仅在您想在每次触摸行时更新 OrderDate 值时才真正有效,即使那里已经有一个值并且如果向参数提供了一个值... 【参考方案3】:为了遵守 DRY,一种解决方法是将您的默认值存储在一个表中:
CREATE TABLE dbo.MyDefaults
(
OrderState INT
);
INSERT dbo.MyDefaults(OrderState) SELECT 0;
你不能用 GETDATE() 真正做到这一点,所以让我们保持原样 - 无论如何,你可能不会改变它。所以现在我们可以从表中提取我们的默认值,而不是硬编码它。让我们创建一个标量函数,因为我们不能在默认约束中使用子查询:
CREATE FUNCTION dbo.DefaultOrderState()
RETURNS INT
AS
BEGIN
RETURN (SELECT TOP (1) OrderState FROM dbo.MyDefaults);
END
GO
(如果您有很多这些,您可能会考虑使用EAV 方法而不是专用列。)
所以现在我们可以拥有 Orders 表,并注意从未提及常量“0”:
CREATE TABLE dbo.Orders
(
O_ID INT NOT NULL,
[State] INT NOT NULL DEFAULT (dbo.DefaultOrderState()),
P_ID INT,
OrderDate DATE NOT NULL DEFAULT (SYSDATETIME())
);
GO
而且我们的更新过程也可以获取默认值(除非您没有定义如果当前不是 0 并且没有向过程提供值,您是否真的要将状态重置为 0)。同样没有提到“0”常数。
CREATE PROCEDURE dbo.UpdateOrder
@O_ID INT,
@State INT = NULL,
@P_ID INT,
@OrderDate DATE = NULL
AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.Orders
SET [State] = COALESCE(@State, dbo.DefaltOrderState()),
P_ID = @P_ID,
OrderDate = COALESCE(@OrderDate, OrderDate, SYSDATETIME())
WHERE
O_ID = @O_ID;
END
GO
【讨论】:
【参考方案4】:对于更新,您可以为“无更改”发送 null(如果该列可以为空,则可以发送另一个哨兵)。类似的方法适用于插入。
CREATE PROCEDURE UpdateOrder
(
@O_ID INT
,@State INT
,@P_ID INT = -1
,@OrderDate DATE
)
AS
UPDATE
Orders
SET
State = IsNull(@State,State)
,P_ID = case when @P_ID < 0 then P_ID else @P_ID end -- assuming this int is not nullable and something like -1 is the default value
,OrderDate = COALESCE(@OrderDate,OrderDate)
WHERE
O_ID = @O_ID
【讨论】:
以上是关于SQL 默认值 - 最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章