【问题标题】:Update ANSI_NULLS option in an existing table更新现有表中的 ANSI_NULLS 选项
【发布时间】:2012-04-18 02:20:22
【问题描述】:

在我们的数据库中有一个使用ANSI_NULLS OFF 创建的表。现在我们已经使用这个表创建了一个视图。我们想为这个视图添加一个聚集索引。

在创建聚集索引时,它会显示一个错误,例如无法创建索引,因为此特定表的 ANSI_NULL 已关闭。

此表包含大量数据。所以我想在不丢失任何数据的情况下将此选项更改为 ON。

有什么办法可以修改表来修改这个选项。请提出您的建议。

【问题讨论】:

    标签: sql sql-server-2008 clustered-index ansi-nulls


    【解决方案1】:

    我尝试了上面推荐的 SWITCH 选项,但无法重新设置身份。我找不到原因。

    我使用了以下替代方法:

    1. 为包含该表的数据库创建数据库快照
    2. 您要更新的表的脚本表定义
    3. 删除要更新的表(确保数据库快照创建成功)
    4. 从第 2 步获得的脚本中将 SET ANSI NULL 从 OFF 更新为 ON,并运行更新的脚本。表现已重新创建。
    5. 将数据库快照中的数据填充到您的表中: SET IDENTITY_INSERT TABLE_NAME ON INSERT INTO TABLE_NAME (PK, col1, etc.) SELECT PK, col1, etc. FROM [Database_Snapshot].dbo.TABLE_NAME SET IDENTITY_INSERT TABLE_NAME OFF
    6. 手动迁移非聚集索引(从数据库快照获取脚本)

    使用上面的:

    • 我不必担心约束和键,因为表/约束名称始终保持不变(我不需要重命名任何内容)
    • 我有我的数据(快照)的备份,我可以依靠它来仔细检查是否缺少任何内容。
    • 我不需要重新设定身份

    我意识到如果表在其他表中被引用,删除表可能并不总是那么简单。在这种情况下,我不是这种情况。我很幸运。

    【讨论】:

      【解决方案2】:

      这是cross posted on Database Administrators,所以我也不妨从那里发布我的答案,以帮助未来的搜索者。

      可以使用ALTER TABLE ... SWITCH 仅更改元数据(即无需将所有数据迁移到新表)。

      下面的示例代码

      /*Create table with option off*/ 
      SET ANSI_NULLS OFF; 
      
      CREATE TABLE dbo.YourTable (X INT) 
      
      /*Add some data*/ 
      INSERT INTO dbo.YourTable VALUES (1),(2),(3) 
      
      /*Confirm the bit is set to 0*/ 
      SELECT uses_ansi_nulls, * 
      FROM   sys.tables 
      WHERE  object_id = object_id('dbo.YourTable') 
      
      GO 
      
      BEGIN TRY 
          BEGIN TRANSACTION; 
          /*Create new table with identical structure but option on*/
          SET ANSI_NULLS ON; 
          CREATE TABLE dbo.YourTableNew (X INT) 
      
          /*Metadata only switch*/
          ALTER TABLE dbo.YourTable  SWITCH TO dbo.YourTableNew;
      
          DROP TABLE dbo.YourTable; 
      
          EXECUTE sp_rename N'dbo.YourTableNew', N'YourTable','OBJECT'; 
      
          /*Confirm the bit is set to 1*/ 
          SELECT uses_ansi_nulls, * 
          FROM   sys.tables 
          WHERE  object_id = object_id('dbo.YourTable') 
      
          /*Data still there!*/ 
          SELECT * 
          FROM dbo.YourTable
      
          COMMIT TRANSACTION; 
      END TRY 
      
      BEGIN CATCH 
          IF XACT_STATE() <> 0 
            ROLLBACK TRANSACTION; 
      
          PRINT ERROR_MESSAGE(); 
      END CATCH; 
      

      警告:当您的表包含 IDENTITY 列时,您需要重新设定 IDENTITY 值。 SWITCH TO 将重置标识列的种子,如果您对标识没有 UNIQUE 或 PRIMARY KEY 约束(例如,在 SQL 2014 中使用 CLUSTERED COLUMNSTORE 索引时),您不会立即注意到它。 您需要使用 DBCC CHECKIDENT ('dbo.YourTable', RESEED, [reseed value]) 重新正确设置种子值。

      【讨论】:

      • 这样会保留原表的所有索引和约束吗?
      • 不,它不会保留所有索引和约束。
      • @xav 如果您将它们包含在create table 中,它会。
      • @MartinSmith 正确,我过早发布了我的评论。我的观点是 switch 命令本身不会处理它们。它们必须作为创建表脚本的一部分或单独创建。对于非聚集索引,我个人必须单独创建它们(并使用差异工具使该过程更容易)。我认为在 SSMS 中在暂存/临时表和结束表之间进行快速视觉差异以确保不会忘记任何内容并没有什么坏处。另外,我准备好了数据库快照,以防我搞砸了(测试环境),但那是因为我偏执。
      • @MartinSmith,顺便谢谢你的回答。它解决了我的问题。
      【解决方案3】:

      不幸的是,如果不重新创建,就无法做到这一点。您需要使用ANSI_NULLS ON 创建新表并将所有数据复制到那里。

      应该是这样的:

      SET ANSI_NULLS ON;
      
      CREATE TABLE new_MyTBL (
      ....
      )
      
      -- stop all processes changing your data at this point
      
      SET IDENTITY_INSERT new_MyTBL ON
      
      INSERT new_MyTBL (...)   -- including IDENTITY field 
      SELECT ...               -- including IDENTITY field 
      FROM MyTBL 
      
      SET IDENTITY_INSERT new_MyTBL OFF
      
      -- alter/drop WITH SCHEMABINDING objects at this point
      
      EXEC sp_rename @objname = 'MyTBL', @newname = 'old_MyTBL'
      EXEC sp_rename @objname = 'new_MyTBL', @newname = 'MyTBL'
      
      -- alter/create WITH SCHEMABINDING objects at this point
      -- re-enable your processes
      
      DROP TABLE old_MyTBL      -- do that when you are sure that system works OK
      

      如果有任何依赖对象,它们将在您重命名新表后立即使用。但如果其中一些是WITH SCHEMABINDING,则需要手动输入DROPCREATE

      【讨论】:

      • 我们有一个与此表关联的视图。那么在不影响视图和关联表的情况下,将数据从该表迁移到新创建的表的最佳方法是什么??
      • 是的,我们使用模式绑定选项创建了视图。我们可以更改视图以删除模式绑定,然后运行您的查询。有可能吗?
      • 您的观点是否被编入索引?使它们成为模式绑定的原因是什么?
      • 是的,我们将对我们的视图进行全文索引。同样,身份字段呢。如何不受影响?
      • 您不需要将所有数据复制到新表中并删除并重新创建所有索引。只需更新表元数据就可以做到这一点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-25
      • 1970-01-01
      相关资源
      最近更新 更多