Ich habe eine smalldatetime-Spalte, die ich ändern muss, um eine Datetime-Spalte zu sein. Dies ist Teil eines Installationsprozesses und kann daher nicht manuell durchgeführt werden. Leider hat die Spalte einige Indizes und eine Nicht-Null-Einschränkung. Die Indizes sind leistungsbezogen und müssen nur unter Verwendung des neuen Datentyps beibehalten werden. Ist es möglich, eine Aussage zu schreiben, die es mir erlaubt, die relevanten Informationen beizubehalten und gleichzeitig den Spaltentyp zu ändern? Wenn ja, wie kann dies getan werden?SQL-Indizes beim Ändern des Spaltentyps erhalten
Antwort
Sie können den Datentyp von small mit den Indizes in Datetime ändern, eindeutige Einschränkungen, Fremdschlüssel-Constraints oder überprüfen Einschränkungen vorhanden. Sie müssen alle löschen, bevor Sie den Typ ändern. Dann:
alter table T alter column TestDate datetime not null
Dann neu erstellen Sie die Einschränkungen und Indizes, die noch gelten.
Einige unterschiedliche Ansätze für den Abfall zu erzeugen und erzeugt:
1) Wenn Sie auf alle Indizes und Constraints explizite Namen gegeben haben, dann mit Ihrem Installateur ein statisches Skript in jeder Umgebung ausgeführt werden können (dev, test, Benutzerakzeptanztests, Leistungstest usw. Produktion.)
Um dieses explizite Skript zu erstellen, können Sie: a) Verwenden Sie SSMS (oder mit SQL Server 2000, Enterprise Manager), um die Erstellungs- und die Anweisung zu senden. b) Arbeiten Sie von Ihrem Quellcode-Repository aus, um die Namen und Definitionen der abhängigen Objekte zu ermitteln und das entsprechende statische Skript zusammenzustellen. c) Versuch, die alter-Anweisung auszuführen. Sehen Sie, worauf es scheitert. Nachschlagen Sie die Definitionen und schreiben Sie den Tropfen und erstellen Sie ihn. (Persönlich wäre das großartig, um den Tropfen zu schreiben, nicht so gut beim Erstellen.)
2) Wenn Sie nicht allen Indizes und Einschränkungen explizite Namen gegeben haben, muss Ihr Installer das Data Dictionary nach den entsprechenden Namen abfragen und Dynamic SQL verwenden, um die Drops in der richtigen Reihenfolge auszuführen die alter column-Anweisung und dann das Erstellen in der richtigen Reihenfolge nach der alter-Spalte.
Dies ist einfacher, wenn Sie wissen, dass es keine Einschränkungen und nur Indizes gibt.
Es kann Werkzeuge oder Bibliotheken geben, die bereits wissen, wie das geht.
Wenn dies eine gepackte Anwendung ist, können Sie nicht sicher sein, dass die lokalen DBAs keine Indizes hinzugefügt haben.
HINWEIS: Wenn eine eindeutige Einschränkung vorhanden ist, wird ein Index erstellt, den Sie nicht mit DROP INDEX löschen können.
BEARBEITEN: Es hängt vom ursprünglichen und geänderten Datentyp ab. Wenn Sie versuchen, eine Spalte von varchar in nvarchar zu ändern, schlägt sie fehl. Wenn Sie hingegen die Spalte von varchar (16) zu varchar (32) ändern, wird es erfolgreich sein.
--Disable Index
ALTER INDEX MyIndex ON MyTable DISABLE
GO
-- Change column datatype
--Enable Index
ALTER INDEX MyIndex ON MyTable REBUILD
GO
Wenn Sie den Typ einer Spalte zu ändern, dann werden alle Indizes, die diese Spalte verwenden müssen neu aufgebaut werden.
Aber wenn Sie keine riesigen Datenmengen haben (oder 24/7 laufen), ist der Neuaufbau von Indizes keine große Sache. Planen Sie einfach ein Wartungsfenster.
Was gut wäre, denke ich, für Phillip, solange sie dabei bleiben und mit dem neuen automatisch neu aufgebaut werden Datentyp. – Thilo
Wenn ich versuche, und führen Sie ALTER INDEX [MyIndex] auf [MyTable] SPERREN ich den Fehler „falsche Syntax nahe dem Schlüsselwort‚INDEX‘zu bekommen. Bin ich etwas fehlt? –
Da dieser Kommentar verfasst ich, dass SQL Server gefunden haben 2000 erlaubt Ihnen nicht, einen Index zu deaktivieren.Es muss gelöscht und erstellt werden.Wir haben ein paar Server, die immer noch auf SQL Server 2000 sind, so dass der Befehl Deaktivieren für mich nicht funktioniert. –
Wenn Sie nur die Größe ändern, bleibt der Index weiterhin auf dem Tisch.
Wenn Sie den Datentyp ändern, erhalten Sie eine Fehlermeldung, dass Objekte von der Spalte abhängig sind, die Sie ändern möchten. Daher können Sie sie nicht ändern.
Sie können die betreffenden Indexe manuell oder per Skript scripten. Klicken Sie in SSMS mit der rechten Maustaste auf die Tabelle, und scripten Sie das betreffende Objekt aus.
Wenn Sie programmatisches Index-Scripting wollen, hier ist ein gespeicherter proc, den ich benutzt habe, den ich von einem ehemaligen Kollegen von mir bekommen habe.
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
Dies ist ein sehr nützlicher SP, unterscheidet jedoch nicht zwischen Spalten in Index- und eingeschlossenen Spalten und bedroht auf diese Weise alle Spalten als gleich. –
Am besten erstellen Sie eine Prozedur, die das Indexskript einer bestimmten Tabelle/Spalte zurückgibt. So können Sie die Indizes nur aus der zu ändernden Spalte und nicht alle Indizes aus der Tabelle entfernen, während das Erstellen von Indizes etwas teuer sein kann.
- Speichert das Ergebnis des Verfahrens in einer Datentabelle
- Löschen Sie die Indizes der Spalte
- Ändern Sie bitte Ihre Spalte
die Indizes in der Datentabelle
gespeichert Rebuild-- 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. Ändern des booleschen Spaltentyps in int
- 2. Ändern des Spaltentyps der Liste aus Lookup in Sharepoint
- 3. Hive - Name des Spaltentyps zu lang
- 4. Verwenden des Uniqueidentifier-SQL-Spaltentyps mit dem Entity-Framework
- 5. EF5-Code zuerst - Ändern eines Spaltentyps mit Migrationen
- 6. Ändern eines Spaltentyps mit Daten, ohne die Daten zu löschen
- 7. Probleme beim Ändern des Etikettentextes
- 8. Ändern des Cursors beim Ziehen
- 9. Git beim Ändern des Repository
- 10. Fehler beim Entschlüsseln des Saml-Tokens erhalten
- 11. Erhalten Attributfehler beim Überprüfen des Modells
- 12. Fehler beim Abrufen des angegebenen Indexobjekts erhalten
- 13. Rendering Probleme beim Ändern des Designs
- 14. C# RotateTransform - Probleme beim Ändern des Mittelpunkts
- 15. Inhalt des übermittelten Formulars beim Einreichen ändern
- 16. Tomcat Setup Fehler beim Ändern des Ports
- 17. Bash whiptail stirbt beim Ändern des Verzeichnisses
- 18. Ändern Höhe des Elements beim Ändern der Fenstergröße
- 19. Ändern des beobachtbaren Streams beim Beibehalten des Abonnements
- 20. Größe des ziehbaren Elements beim Start des Ziehens ändern
- 21. Arbeitsverzeichnis des Testlaufkäfigs ändern
- 22. Problem beim Erhalten des FadeIn-Elements zum Erhöhen
- 23. Ändern des Animationsziels
- 24. kann keine WHERE-Klausel auf den Zeitstempel des Spaltentyps anwenden, dessen Name "when" lautet.
- 25. Ändern Spinner Inhalt beim Öffnen
- 26. Fehler beim Entpacken erhalten
- 27. erhalten einen Segmentierungsfehler beim Ausdrucken von Wörtern des Arrays
- 28. Link erhalten Fehler beim Zurücksetzen des Passworts mit fosuserbundle, symfony2
- 29. Radiobutton/Checkbox bleibt beim Ändern des Status aktiviert
- 30. Ändern des Prozessnamens beim Starten als Batch-Datei
Ich konnte die Quelle sql hinter der Erstellung der Indizes finden und war in der Lage, diese zu verwenden, um diese zu löschen, bevor der Typ geändert wurde. Was die Einschränkung betrifft, habe ich eine Abfrage über Google gefunden, die verwendet werden kann, um den zufällig generierten Constraint-Namen zu bestimmen. –
Deklarieren @constraintName als nvarchar (100) Deklarieren @sql nvarchar (1000) \t select @constraintName = O.name \t aus sysobjects AS O \t links sysobjects AS T \t \t auf O.parent_obj = T. beitreten ID \t wo isnull (objectproperty (O.id, 'IsMSShipped'), 1) = 0 \t \t und O.Name nicht gefallen '% dtproper%' \t \t O.name und nicht wie 'dt [_]%' \t \t und T.name = 'MyTable' \t \t und O.name wie 'DF__MyTabl__MyCol%' \t wenn nicht @constraintName null ist \t beginnen \t \t wählen @sql = 'ALTER TABLE [MyTable] DROP CONSTRAINT [' + @constraintName + ']' \t \t ausführen sp_executesql @sql \t Ende –