我有一個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. SQL:更新列,其索引在列更改時重置
- 4. SQL在更新後保留數據
- 5. Postgresql - 將列類型從oid更改爲具有數據保留的bytea
- 6. Sql Server更改數據捕獲:添加列時保留歷史記錄?
- 7. 在禁用外鍵約束和索引之前更改列的數據類型
- 8. SQL Server - SQL級聯更改列的數據類型
- 9. 在SQL Server中更改列數據類型的最快方法
- 10. SQL Server更改主鍵數據類型
- 11. SQL Server總和更改數據類型
- 12. 數據類型和索引
- 13. 如何在列數據類型和值更改時保持Mysql高可用性?
- 14. 熊貓 - 索引類型值的更改
- 15. 在SQL Server Management Studio中更改SQL Server數據庫中的列索引
- 16. 將Solr從單核更改爲多核,希望保留索引數據
- 17. 更改會話ID並保留數據?
- 18. 從列表中創建Pandas數據框,同時保留數據類型
- 19. 更改表列的數據類型
- 20. 更改列數據類型翻番
- 21. null列更改數據類型
- 22. 更改列的數據類型
- 23. 更改NVARCHAR到VARCHAR列數據類型
- 24. 更改列值數據類型(日期)
- 25. 更改所有列WHERE數據類型
- 26. 更改列數據類型和格式
- 27. 將熊貓系列添加到數據框中,保留索引
- 28. Android webview在方向更改時保留表單數據
- 29. 想要在更改爲其他UIView時保留緩存數據
- 30. Google Charts:如何在更改數據時保留縮放
我能夠在創建索引後找到源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