Ho una colonna smalldatetime che devo modificare per essere una colonna datetime. Questo è qualcosa che farà parte di un processo di installazione, quindi non può essere una procedura manuale. Sfortunatamente, la colonna ha alcuni indici e un vincolo non nullo su di essa. Gli indici sono correlati alle prestazioni e dovrebbero essere mantenuti solo utilizzando il nuovo tipo di dati. È possibile scrivere una dichiarazione che mi consenta di conservare le informazioni pertinenti mentre altero ancora il tipo di dati della colonna? Se è così, come può essere fatto?Mantieni gli indici SQL durante la modifica del tipo di dati colonna
risposta
Non è possibile modificare il tipo di dati da smalldatetime in datetime con gli indici, vincoli univoci, vincoli di chiave esterna o controllare i vincoli al suo posto. Dovrai lasciarli tutti prima di cambiare il tipo. Quindi:
alter table T alter column TestDate datetime not null
Quindi ricreare i vincoli e gli indici che si applicano ancora.
Alcuni approcci diversi per la generazione della goccia e crea:
1) Se avete dato nomi espliciti per tutti gli indici ei vincoli allora il vostro installatore può eseguire uno script statica in ogni ambiente (dev, prova, . utente test di accettazione, test delle prestazioni, ecc, produzione)
per generare questo script esplicito è possibile: a) Utilizzare SQL Server Management Studio (o con SQL Server 2000, enterprise Manager) per lo script le dichiarazioni creare e rilasciare. b) Lavora dal tuo repository del codice sorgente per scoprire i nomi e le definizioni degli oggetti dipendenti e mettere insieme lo script statico appropriato. c) Tentativo di eseguire l'istruzione alter. Guarda cosa fallisce. Cerca le definizioni e scrivi la goccia e crea. (Personalmente, questo sarebbe fantastico per scrivere il drop, non così bravo nel creare.)
2) Se non sono stati forniti nomi espliciti per tutti gli indici e i vincoli, il programma di installazione dovrà interrogare il dizionario dei dati per i nomi appropriati e utilizzare SQL dinamico per eseguire le gocce, nell'ordine corretto, prima di l'istruzione alter column e quindi crea, nell'ordine corretto, dopo la colonna alter.
Questo sarà più semplice se si sa che non ci sono vincoli e solo indici.
Ci possono essere strumenti o librerie che già sanno come fare questo.
Inoltre, se si tratta di un'applicazione pacchettizzata, potrebbe non essere sicuro che gli amministratori di database locali non abbiano aggiunto indici.
NOTA: se esiste un vincolo univoco, avrà creato un indice, che non sarà possibile eliminare con DROP INDEX.
MODIFICA: Dipende dal tipo di dati originale e modificato. Se si tenta di modificare una colonna da varchar a nvarchar, fallirà. Considerando che, se si modifica la colonna da varchar (16) a varchar (32), avrà successo.
--Disable Index
ALTER INDEX MyIndex ON MyTable DISABLE
GO
-- Change column datatype
--Enable Index
ALTER INDEX MyIndex ON MyTable REBUILD
GO
Se si modifica il tipo di una colonna, sarà necessario ricostruire tutti gli indici che utilizzano tale colonna.
Ma a meno che non si disponga di enormi volumi di dati (o eseguiti 24 ore su 24, 7 giorni su 7), la ricostruzione degli indici non è un grosso problema. Basta programmare una finestra di manutenzione.
Il che andrebbe bene, suppongo, per Phillip, a patto che rimangano incollati e ricostruiti automaticamente usando il nuovo tipo di dati. – Thilo
Quando provo e faccio funzionare ALTER INDEX [MyIndex] su [MyTable] disabilita ottengo l'errore "Sintassi non corretta in prossimità della parola chiave 'INDEX'. Mi sto perdendo qualcosa? –
Dal distacco questo commento ho trovato che SQL Server 2000 non consente di disabilitare un indice, deve essere eliminato e creato. Abbiamo alcuni server che sono ancora su SQL Server 2000, quindi il comando disable non funzionerà per me. –
Se si modifica solo la dimensione, l'indice rimarrà sul tavolo.
Se si modifica il tipo di dati, verrà visualizzato un messaggio di errore che indica che gli oggetti dipendono dalla colonna che si sta tentando di modificare e pertanto non sarà possibile modificarlo.
È possibile eseguire lo script degli indici in questione manualmente o tramite script. In SSMS, fare clic con il pulsante destro del mouse sulla tabella e creare lo script per l'oggetto in questione.
Se si desidera lo script di indice programmatico, ecco un processo memorizzato che ho utilizzato che ho ricevuto da un mio ex collega.
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
Questo è molto utile SP, ma non fa distinzione tra le colonne nell'indice e le colonne incluse e in questo modo minaccia tutte le colonne come stesse. –
La cosa migliore da fare è creare una procedura che restituisca lo script indice di una determinata tabella/colonna. Quindi è possibile rimuovere gli indici solo dalla colonna che viene modificata e non tutti gli indici dalla tabella, mentre la creazione di indici può essere piuttosto costosa.
- Memorizza il risultato della procedura in un DataTable
- Elimina gli indici della colonna
- Modifica la colonna
ricostruire gli indici memorizzati nella 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. MS Access SQL, modifica del tipo di dati
- 2. SQL Server: controllo del tipo di dati di una colonna
- 3. La ricostruzione degli indici non modifica la percentuale di frammentazione per gli indici non cluster
- 4. Mantieni l'ordine degli attributi durante la modifica con minidom
- 5. Errore durante la conversione del tipo di dati varchar
- 6. Modifica il tipo di dati di una colonna in serie
- 7. Come si modifica il tipo di dati di una colonna in MS SQL?
- 8. "Errore durante la conversione del tipo di dati varchar in numerico." - Quale colonna?
- 9. T-SQL "timestamp" sovrascrive "rowversion" tipo di dati di colonna
- 10. Modifica panda DataFrame usando gli indici
- 11. Mantieni visibile la colonna sinistra E scorrevole
- 12. Cambia tipo di colonna senza perdere dati
- 13. Eccezione Sql: errore durante la conversione del tipo di dati numerico in numerico
- 14. t-sql: Errore durante la conversione del tipo di dati varchar in numerico nell'istruzione then
- 15. Mantieni il contenuto del database sulla modifica del modello
- 16. Modifica del tipo di una colonna utilizzata in altre viste
- 17. Modifica del tipo di dati di una colonna in una tabella ENORME. Prestazioni emette
- 18. modifica dati evento durante la propagazione
- 19. Indici filtrati dal server SQL
- 20. mongodb non utilizza gli indici durante l'ordinamento?
- 21. Modifica di un tipo di colonna con dati, senza cancellare i dati
- 22. Mantieni il tipo di dati della colonna Dataframe dopo l'unione esterna
- 23. Accelerazione di una query SQL con indici
- 24. Modifica un tipo di colonna in sqlite3
- 25. Gli indici DB occupano la stessa quantità di spazio su disco dei dati delle colonne?
- 26. SQL Compact Edition supporta gli indici clusterizzati?
- 27. Gli indici server Sql includono la chiave primaria?
- 28. Come si modifica il tipo di dati Colonna tabella su più di una colonna?
- 29. SQL: cosa fanno esattamente le chiavi primarie e gli indici?
- 30. Come sapere quando utilizzare gli indici e quale tipo?
Sono stato in grado di trovare la fonte sql dietro la creazione degli indici ed è stato in grado di utilizzare quelli per eliminarli prima di modificare il tipo. Per quanto riguarda il vincolo, ho trovato una query tramite google che può essere utilizzata per determinare il nome del vincolo generato casualmente. –
dichiarare @constraintName come nvarchar (100) dichiarare nvarchar @sql (1000) \t selezionare @constraintName = O.name \t da sysobjects AS O \t left join sysobjects AS T \t \t su O.parent_obj = T. id \t dove isnull (objectproperty (O.id, 'IsMSShipped'), 1) = 0 \t \t e O.Nome non come '% dtproper%' \t \t e O.name non come 'dt [_]%' \t \t e T.name = 'MyTable' \t \t e O.name come 'DF__MyTabl__MyCol%' \t se non è nulla @constraintName \t iniziano \t \t selezionare @sql = 'ALTER TABLE [MyTable] CADUTA CONSTRAINT [' + @constraintName + ']' \t \t eseguire sp_executesql @sql \t fine –