在更改列数据类型时保留SQL索引

Phi*_*ges 18 sql t-sql sql-server

我有一个smalldatetime列,我需要将其更改为datetime列.这是安装过程的一部分,因此它不能是手动过程.不幸的是,该列有一些索引和一个非空约束.索引与性能相关,只需使用新数据类型即可保留.是否有可能编写一个语句,允许我在更改列数据类型的同时保留相关信息?如果是这样,怎么办呢?

Sha*_*nce 14

您无法使用索引,唯一约束,外键约束或检查约束将数据类型从smalldatetime更改为datetime.在更改类型之前,您必须将它们全部丢弃.然后:

alter table T alter column TestDate datetime not null
Run Code Online (Sandbox Code Playgroud)

然后重新创建仍然适用的约束和索引.


生成drop和创建的一些不同方法:

1)如果您已为所有索引和约束指定了明确的名称,那么您的安装程序可以在每个环境中运行静态脚本(开发,测试,用户验收测试,性能测试等,生产.)

要生成此显式脚本,您可以:a)使用SSMS(或SQL Server 2000,企业管理器)编写create和drop语句的脚本.b)从您的源代码存储库开始工作,以发现依赖对象的名称和定义,并将相应的静态脚本放在一起.c)尝试运行alter语句.看看它失败了.查找定义并手写drop和create.(就个人而言,这对于编写drop而言非常棒,而在创建时则不是很好.)

2)如果您没有为所有索引和约束指定明确的名称,那么安装程序必须在数据字典中查询相应的名称,并使用动态SQL以正确的顺序运行drop,在alter column语句之前和然后在alter列之后以正确的顺序创建.

如果您知道没有约束,只有索引,这将更简单.

可能有工具或库已经知道如何执行此操作.

此外,如果这是一个打包的应用程序,您可能无法确保本地DBA没有添加索引.

注意:如果存在唯一约束,它将构建一个索引,您将无法使用DROP INDEX删除该索引.


Raj*_*ore 9

如果您只是更改大小,索引仍将保留在表中.

如果要更改数据类型,则会收到一条错误消息,指出对象依赖于您尝试更改的列,因此您将无法更改它.

您可以手动或通过脚本编写有问题的索引.在SSMS中,右键单击该表并编写相关对象的脚本.

如果你想要编程索引脚本,这里是我一直在使用的存储过程,我是从我的前同事那里得到的.

Drop Proc ScriptIndex
GO
Create Proc ScriptIndex
    @TableName      VarChar (Max),
    @IndexScript    VarChar (Max) OUTPUT
AS

-- Get all existing indexes, EXCEPT the primary keys
DECLARE cIX CURSOR FOR
SELECT OBJECT_NAME(SI.Object_ID), SI.Object_ID, SI.Name, SI.Index_ID
FROM Sys.Indexes SI 
    LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC 
        ON SI.Name = TC.CONSTRAINT_NAME 
        AND OBJECT_NAME(SI.Object_ID) = TC.TABLE_NAME
WHERE 1=1
    AND OBJECT_NAME(SI.Object_ID) = @TableName
    AND TC.CONSTRAINT_NAME IS NULL
    AND OBJECTPROPERTY(SI.Object_ID, 'IsUserTable') = 1
ORDER BY OBJECT_NAME(SI.Object_ID), SI.Index_ID

DECLARE @IxTable SYSNAME
DECLARE @IxTableID INT
DECLARE @IxName SYSNAME
DECLARE @IxID INT

-- Loop through all indexes
OPEN cIX
FETCH NEXT FROM cIX INTO @IxTable, @IxTableID, @IxName, @IxID
WHILE (@@FETCH_STATUS = 0)
BEGIN
   DECLARE @IXSQL NVARCHAR(4000) 
   DECLARE @PKSQL NVARCHAR(4000) 
   SET @PKSQL = ''
   SET @IXSQL = 'CREATE '

   -- Check if the index is unique
   IF (INDEXPROPERTY(@IxTableID, @IxName, 'IsUnique') = 1)
      SET @IXSQL = @IXSQL + 'UNIQUE '
   -- Check if the index is clustered
   IF (INDEXPROPERTY(@IxTableID, @IxName, 'IsClustered') = 1)
      SET @IXSQL = @IXSQL + 'CLUSTERED '

   SET @IXSQL = @IXSQL + 'INDEX ' + @IxName + ' ON ' + @IxTable + '('

   -- Get all columns of the index
   DECLARE cIxColumn CURSOR FOR 
      SELECT SC.Name
      FROM Sys.Index_Columns IC
         JOIN Sys.Columns SC ON IC.Object_ID = SC.Object_ID AND IC.Column_ID = SC.Column_ID
      WHERE IC.Object_ID = @IxTableID AND Index_ID = @IxID
      ORDER BY IC.Index_Column_ID

   DECLARE @IxColumn SYSNAME
   DECLARE @IxFirstColumn BIT SET @IxFirstColumn = 1

   -- Loop throug all columns of the index and append them to the CREATE statement
   OPEN cIxColumn
   FETCH NEXT FROM cIxColumn INTO @IxColumn
   WHILE (@@FETCH_STATUS = 0)
   BEGIN
      IF (@IxFirstColumn = 1)
         SET @IxFirstColumn = 0
      ELSE
         SET @IXSQL = @IXSQL + ', '

      SET @IXSQL = @IXSQL + @IxColumn

      FETCH NEXT FROM cIxColumn INTO @IxColumn
   END
   CLOSE cIxColumn
   DEALLOCATE cIxColumn

   SET @IXSQL = @IXSQL + ')'
   -- Print out the CREATE statement for the index
   PRINT @IXSQL

   FETCH NEXT FROM cIX INTO @IxTable, @IxTableID, @IxName, @IxID
END

CLOSE cIX
DEALLOCATE cIX

GO
Declare @TableName VarChar (Max), @IndexScript VarChar (Max)

Exec ScriptIndex 'Client', @IndexScript OUTPUT
Print @IndexScript
Run Code Online (Sandbox Code Playgroud)