【问题标题】:SQL defaults - best practice?SQL 默认值 - 最佳实践?
【发布时间】: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 列的更好的数据类型选择。

标签: sql-server sql-server-2008 default parameter-passing constraints


【解决方案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
      

      【讨论】:

        猜你喜欢
        • 2012-07-20
        • 2016-08-08
        • 2015-10-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-04
        • 2011-02-06
        • 1970-01-01
        相关资源
        最近更新 更多