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 默认值 - 最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章

在一定时间后自动更改 SQL 服务器记录的最佳实践?

默认成员值最佳实践

设置应该是 Python 列表的参数的默认值的最佳实践?

将可空整数初始化为默认值的最佳实践?

通过c#代码检索存储在sql表中的Json值的最佳实践

Perl 最佳实践(节选) --- 09