我有一个smalldatetime列,我需要将其更改为datetime列。这是安装过程的一部分,因此它不能是手动过程。不幸的是,该列有一些索引和一个非空约束。索引与性能相关,只需使用新的数据类型即可保留。是否有可能编写一个声明,使我可以在保留相关信息的同时更改列数据类型?如果是这样,这怎么办?在更改列数据类型时保留SQL索引
回答
您不能使用索引,唯一约束,外键约束或检查约束将数据类型从smalldatetime更改为datetime。在更改类型之前,您必须先删除它们。然后:
alter table T alter column TestDate datetime not null
然后重新创建仍然适用的约束和索引。
产生下降一些不同的方法,并创建:
1)如果你给了明确的名称所有的索引和约束那么你的安装程序可以运行在每个环境(静态脚本开发,测试,用户验收测试,性能测试等,生产)。
要生成此显式脚本,您可以: a)使用SSMS(或与SQL Server 2000企业管理器一起)编写创建和删除语句的脚本。 b)从你的源代码仓库开始寻找依赖对象的名称和定义,并将适当的静态脚本放在一起。 c)尝试运行alter语句。看看它失败了。查找定义并手写下降并创建。 (就个人而言,写这篇文章会很好,但对创作并不那么擅长。)
2)如果您尚未给所有索引和约束指定明确的名称,则安装程序必须查询数据字典以获取适当的名称,并使用动态SQL以正确的顺序在alter column语句,然后按照正确的顺序在alter列后创建。
如果你知道没有约束并且只是索引,这将会更简单。
可能有工具或库已经知道如何做到这一点。另外,如果这是一个打包的应用程序,您可能无法确定本地DBA没有添加索引。
注意:如果存在唯一约束,它将构建一个索引,您将无法使用DROP INDEX删除该索引。
编辑:它取决于原始和更改的数据类型。 如果尝试将varchar列更改为nvarchar,则该列将失败。 而如果将varchar(16)中的列更改为varchar(32),则它将成功。
--Disable Index
ALTER INDEX MyIndex ON MyTable DISABLE
GO
-- Change column datatype
--Enable Index
ALTER INDEX MyIndex ON MyTable REBUILD
GO
如果更改列的类型,那么使用该列的所有索引都必须重新构建。
但是,除非您有大量数据(或全天候运行),否则重建索引是没有什么大不了的。只需安排一个维护窗口。
指标对于菲利普来说,我相信这很好,只要他们坚持使用新的设备就可以自动重建数据类型。 – Thilo 2009-08-11 03:54:07
当我尝试运行 ALTER INDEX [myIndex]对[MyTable的] DISABLE 我得到错误“附近关键字‘INDEX’的语法不正确。我缺少的东西? – 2009-08-11 14:58:13
自发布此评论我发现,SQL服务器2000不允许你禁用一个索引,它必须被删除和创建,我们有一些仍在SQL Server 2000上的服务器,因此禁用命令对我来说不起作用 – 2009-08-11 15:11:46
如果您只是更改大小,索引仍将保留在表格中。
如果您要更改数据类型,那么您将收到一条错误消息,指出对象取决于您要更改的列,因此您将无法对其进行更改。
您可以通过手动或通过脚本来编写问题索引。在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
这是非常有用的SP,但它并不区分索引和包含列中的列,并以此方式威胁所有列相同。 – 2012-11-01 13:25:52
最好的办法是创建一个返回给定表/列的索引脚本的过程。所以你可以从被修改的列中删除索引,而不是从表中删除所有索引,而创建索引可能会有些贵。
- 存储过程的一个DataTable
- 结果中删除列
- 的索引修改您的列
重建存储在数据表
-- objective : Generates indices scripting using specified column -- Parameters : -- @Tabela -> Name of the table that the column belongs to -- @Coluna -> Name of the column that will be searched for the indices to generate the script --Use: proc_ScriptIndexColumn 'TableName', 'CollumnName' SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO Create Proc proc_ScriptIndexColumn (@Tabela VARCHAR(4000), @Coluna VARCHAR(4000)) AS BEGIN DECLARE @isql_key VARCHAR(4000), @isql_incl VARCHAR(4000), @tableid INT, @indexid INT DECLARE @tablename VARCHAR(4000), @indexname VARCHAR(4000) DECLARE @isunique INT, @isclustered INT, @indexfillfactor INT DECLARE @srsql VARCHAR(MAX) DECLARE @ScriptsRetorno TABLE (Script VARCHAR(MAX)) DECLARE index_cursor CURSOR FOR SELECT tablename = OBJECT_NAME(i.[object_id]), tableid = i.[object_id], indexid = i.index_id, indexname = i.name, isunique = i.is_unique, CASE I.type_desc WHEN 'CLUSTERED' THEN 1 ELSE 0 END AS isclustered, indexfillfactor = i.fill_factor FROM sys.indexes AS i INNER JOIN SYSOBJECTS AS O ON I.[object_id] = O.ID INNER JOIN sys.index_columns AS ic ON (ic.column_id > 0 AND (ic.key_ordinal > 0 OR ic.partition_ordinal = 0 OR ic.is_included_column != 0 )) AND ( ic.index_id = CAST(i.index_id AS INT) AND ic.object_id = i.[object_id] ) INNER JOIN sys.columns AS sc ON sc.object_id = ic.object_id AND sc.column_id = ic.column_id WHERE O.XTYPE = 'U' AND i.typE = 2 /*Non clustered*/ AND i.is_unique = 0 AND i.is_hypothetical = 0 AND UPPER(OBJECT_NAME(i.[object_id])) = UPPER(@Tabela) AND UPPER(sc.name) = UPPER(@Coluna) OPEN index_cursor FETCH NEXT FROM index_cursor INTO @tablename,@tableid, @indexid,@indexname , @isunique ,@isclustered , @indexfillfactor WHILE @@fetch_status <> -1 BEGIN SELECT @isql_key = '', @isql_incl = '' SELECT @isql_key = CASE ic.is_included_column WHEN 0 THEN CASE ic.is_descending_key WHEN 1 THEN @isql_key +COALESCE(sc.name, '') + ' DESC, ' ELSE @isql_key + COALESCE(sc.name, '') + ' ASC, ' END ELSE @isql_key END, --include column @isql_incl = CASE ic.is_included_column WHEN 1 THEN CASE ic.is_descending_key WHEN 1 THEN @isql_incl + COALESCE(sc.name, '') + ', ' ELSE @isql_incl + COALESCE(sc.name, '') + ', ' END ELSE @isql_incl END FROM sysindexes i INNER JOIN sys.index_columns AS ic ON ( ic.column_id > 0 AND ( ic.key_ordinal > 0 OR ic.partition_ordinal = 0 OR ic.is_included_column != 0 ) ) AND (ic.index_id = CAST(i.indid AS INT) AND ic.object_id = i.id) INNER JOIN sys.columns AS sc ON sc.object_id = ic.object_id AND sc.column_id = ic.column_id WHERE i.indid > 0 AND i.indid < 255 AND (i.status & 64) = 0 AND i.id = @tableid AND i.indid = @indexid ORDER BY i.name, CASE ic.is_included_column WHEN 1 THEN ic.index_column_id ELSE ic.key_ordinal END IF LEN(@isql_key) > 1 SET @isql_key = LEFT(@isql_key, LEN(@isql_key) -1) IF LEN(@isql_incl) > 1 SET @isql_incl = LEFT(@isql_incl, LEN(@isql_incl) -1) SET @srsql = 'CREATE ' + 'INDEX [' + @indexname + ']' + ' ON [' + @tablename + '] ' SET @srsql = @srsql + '(' + @isql_key + ')' IF (@isql_incl <> '') SET @srsql = @srsql + ' INCLUDE(' + @isql_incl + ')' IF (@indexfillfactor <> 0) SET @srsql = @srsql + ' WITH (FILLFACTOR = ' + CONVERT(VARCHAR(10), @indexfillfactor) + ')' FETCH NEXT FROM index_cursor INTO @tablename,@tableid,@indexid,@indexname, @isunique ,@isclustered , @indexfillfactor INSERT INTO @ScriptsRetorno VALUES (@srsql) END CLOSE index_cursor DEALLOCATE index_cursor SELECT * FROM @ScriptsRetorno RETURN @@ERROR END
- 1. 如何在MySQL中更改列数据类型时保留数据?
- 2. 修改列数据类型时保留数据
- 3. 更改CCAnimation,但保留帧索引
- 4. SQL:更改表的数据列 - 保留列顺序
- 5. 从数据库更新时保留对模型的更改?
- 6. 在Fragment类中更改方向时保留数据
- 7. 更改列数据类型
- 8. SQL:更新列,其索引在列更改时重置
- 9. 熊猫改变索引数据类型
- 10. SQL Server:当基础表数据类型更改时,视图列数据类型不会更改?
- 11. SQL在更新后保留数据
- 12. 更改数据帧索引值,同时保持其他列数据相同
- 13. Postgresql - 将列类型从oid更改为具有数据保留的bytea
- 14. SQL Server +更改列类型
- 15. 更改SQL列类型
- 16. Sql Server更改数据捕获:添加列时保留历史记录?
- 17. 在禁用外键约束和索引之前更改列的数据类型
- 18. SQL Server - SQL级联更改列的数据类型
- 19. Datagridview列索引在绑定到数据表时发生更改
- 20. 在SQL Server中更改列数据类型的最快方法
- 21. 在SQL/ORACLE中将列的数据类型“varchar”更改为“DATE”
- 22. 在SQL Server中更改列的数据类型
- 23. SQL Server总和更改数据类型
- 24. MS Access SQL,更改数据类型
- 25. SQL Server更改主键数据类型
- 26. 合并保留一个索引的SQL数据库
- 27. 数据类型和索引
- 28. 更改选择类型时保留选定的对象
- 29. SQL - 更改字母数字列的数据类型
- 30. Mongodb更新查询保留价值和更新数据类型
我能够在创建索引后找到源sql,并能够在更改类型之前使用它们来删除这些索引。至于约束,我通过google发现了一个查询,可以用来确定随机生成的约束名称。 – 2009-08-11 15:46:55
申报@constraintName如为nvarchar(100) 声明@sql为nvarchar(1000) \t选择@constraintName = O.name \t从系统对象如邻 \t左加入系统对象AS T上O.parent_obj = T. \t \t id \t其中isnull(objectproperty(O.id,'IsMSShipped'),1)= 0 \t \t和O.名不喜欢 '%dtproper%' \t \t和O.name不喜欢 'DT [_]%' \t \t和T.name = 'MyTable的' \t \t和O.name像 'DF__MyTabl__MyCol%' \t如果不是@constraintName为null \t开始 \t \t选择@sql = 'ALTER TABLE [MyTable的] DROP CONSTRAINT [' + @constraintName + ']' \t \t执行sp_executesql的@sql \t端 – 2009-08-11 15:47:32