【问题标题】:SQL Column definition : default value and not null redundant?SQL 列定义:默认值而不是空冗余?
【发布时间】:2012-08-05 10:12:47
【问题描述】:

我已经多次看到以下在创建/更改 DDL 语句中定义列的语法:

ALTER TABLE tbl ADD COLUMN col VARCHAR(20) NOT NULL DEFAULT "MyDefault"

问题是:既然指定了默认值,是否还需要指定该列不应接受 NULL ?换句话说,DEFAULT 不渲染 NOT NULL 是多余的吗?

【问题讨论】:

    标签: sql default-value ddl notnull


    【解决方案1】:

    即使使用默认值,您也始终可以使用null 覆盖列数据。

    NOT NULL 限制不允许您在使用 null 值创建该行后更新该行

    【讨论】:

    • 我认为这应该改写为:“NOT NULL 限制不会让您在使用 null 值创建该行后更新该行”当然可以更新具有 NOT NULL 列的行,它们只是可以' 不更新为 null 作为该列的值。此外:我假设创建一行意味着插入一行。对于用 NOT NULL 指定的列,INSERT 语句也不能有空值。
    【解决方案2】:

    DEFAULT 是在插入/更新语句中没有显式值的情况下将插入的值。假设,您的 DDL 没有 NOT NULL 约束:

    ALTER TABLE tbl ADD COLUMN col VARCHAR(20) DEFAULT 'MyDefault'
    

    那么你可以发布这些声明

    -- 1. This will insert 'MyDefault' into tbl.col
    INSERT INTO tbl (A, B) VALUES (NULL, NULL);
    
    -- 2. This will insert 'MyDefault' into tbl.col
    INSERT INTO tbl (A, B, col) VALUES (NULL, NULL, DEFAULT);
    
    -- 3. This will insert 'MyDefault' into tbl.col
    INSERT INTO tbl (A, B, col) DEFAULT VALUES;
    
    -- 4. This will insert NULL into tbl.col
    INSERT INTO tbl (A, B, col) VALUES (NULL, NULL, NULL);
    

    或者,您也可以根据SQL-1992 标准在UPDATE 语句中使用DEFAULT

    -- 5. This will update 'MyDefault' into tbl.col
    UPDATE tbl SET col = DEFAULT;
    
    -- 6. This will update NULL into tbl.col
    UPDATE tbl SET col = NULL;
    

    请注意,并非所有数据库都支持所有这些 SQL 标准语法。添加NOT NULL 约束将导致语句4, 6 出错,而1-3, 5 仍然是有效语句。所以回答你的问题:不,它们不是多余的。

    【讨论】:

    • 我访问了您的链接(指向您的博客文章),希望看到对查询性能的巨大影响的解释(可能带有一些数字),但只看到它简短地重申了它有影响。无意冒犯,但链接有点误导。
    • @SethFlowers:感谢您的指点,Seth。链接的文章在此期间进行了编辑。我会看看我是否可以链接其他东西,或者删除链接。就目前而言,您是绝对正确的,它不会为这里的答案增加任何价值。
    • 谢谢 - 我希望我没有听起来粗鲁。我刚看到链接,就像“是的,这绝对是我想读的东西”——然后有点失望:)。
    • @SethFlowers:不用担心。我完全同意。拯救我:在过去的几年里,我的博客技巧大大提高了 :)
    【解决方案3】:

    我会说不是。

    如果该列确实接受空值,那么没有什么可以阻止您在字段中插入空值。据我所知,默认值仅适用于创建新行。

    如果设置了非空值,则不能在字段中插入空值,因为它会引发错误。

    将其视为防止空值的故障安全机制。

    【讨论】:

    • 您说的是“创建新规则”。您是否打算说“创建新行”?
    • 我认为这是这个问题的一个更实际的答案。
    • @bielawski 近 8 年后,我开始纠正这个错字:)
    • 这应该是公认的答案。 OP 要求一个简单的问题,而答案只是“不”。但是,文档需要解释和示例。
    【解决方案4】:

    我的SQL老师说过,如果同时指定DEFAULT值和NOT NULLNULLDEFAULT应该总是在NOT NULLNULL之前表达。

    像这样:

    ALTER TABLE tbl ADD COLUMN col VARCHAR(20) DEFAULT "MyDefault" NOT NULL

    ALTER TABLE tbl ADD COLUMN col VARCHAR(20) DEFAULT "MyDefault" NULL

    【讨论】:

    • 您好,感谢您的参与。不过,这并没有解决手头的问题,而且这两种顺序都是完全有效的。当我手动编写表格脚本时,我发现将默认值放在最后更容易,因为这样 NULL 和 NOT NULL 值会更好地对齐。
    • 好吧,我想你也是对的。我不明白为什么我的课程明确地说明了我在答案中所写的内容。我知道我的回答并没有真正解决问题,但我发现评论不是很可读。
    • (主观)最佳实践和规则之间存在差异。拥有一致的风格并不是一个坏主意,但在这种特殊情况下,我个人更喜欢在 DEFAULT 之前使用 NOT NULL。无论如何,您也可以写 cmets 而不是答案,这样会更合适。
    • 这可能无法回答问题。但这正是我想要的。谢谢。
    【解决方案5】:

    换句话说,DEFAULT 不渲染 NOT NULL 冗余吗?

    不,它不是多余的。扩展接受的答案。对于可以为空的列 col,即使定义了 DEFAULT,我们也可以插入 NULL:

    CREATE TABLE t(id INT PRIMARY KEY, col INT DEFAULT 10);
    
    -- we just inserted NULL into column with DEFAULT
    INSERT INTO t(id, col) VALUES(1, NULL);
    
    +-----+------+
    | ID  | COL  |
    +-----+------+
    |   1 | null |
    +-----+------+
    

    Oracle 为这种情况引入了额外的语法,以默认 DEFAULT ON NULL 覆盖显式 NULL:

    CREATE TABLE t2(id INT PRIMARY KEY, col INT DEFAULT ON NULL 10);
    -- same as
    --CREATE TABLE t2(id INT PRIMARY KEY, col INT DEFAULT ON NULL 10 NOT NULL); 
    
    INSERT INTO t2(id, col) VALUES(1, NULL);
    
    +-----+-----+
    | ID  | COL |
    +-----+-----+
    |  1  |  10 |
    +-----+-----+
    

    这里我们尝试插入 NULL 但取而代之的是默认值。

    db<>fiddle demo

    ON NULL

    如果您指定 ON NULL 子句,则 Oracle 数据库会在后续 INSERT 语句尝试分配计算结果为 NULL 的值时分配 DEFAULT 列值。

    当您指定 ON NULL 时,将隐式指定 NOT NULL 约束和 NOT DEFERRABLE 约束状态。

    【讨论】:

      【解决方案6】:

      对于自 12c 以来的 Oracle,您有 DEFAULT ON NULL,这意味着 NOT NULL 约束。

      ALTER TABLE tbl ADD (col VARCHAR(20) DEFAULT ON NULL 'MyDefault');
      

      ALTER TABLE

      为空

      如果您指定 ON NULL 子句,则 Oracle 数据库分配 DEFAULT 列值,当随后的 INSERT 语句尝试 分配一个计算结果为 NULL 的值。

      当您指定 ON NULL 时,NOT NULL 约束和 NOT DEFERRABLE 约束状态是隐式指定的。如果您指定内联 与 NOT NULL 和 NOT DEFERRABLE 冲突的约束,然后是 引发错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-03
        • 2020-06-13
        • 1970-01-01
        • 2016-09-17
        • 2016-08-30
        • 1970-01-01
        • 2019-04-28
        • 1970-01-01
        相关资源
        最近更新 更多