So ändern Sie mehrere Spalten gleichzeitig in SQL Server


143

Ich muss ALTERdie Datentypen mehrerer Spalten in einer Tabelle.

Für eine einzelne Spalte funktioniert Folgendes einwandfrei:

ALTER TABLE tblcommodityOHLC
ALTER COLUMN
    CC_CommodityContractID NUMERIC(18,0) 

Aber wie ändere ich mehrere Spalten in einer Anweisung? Folgendes funktioniert nicht:

ALTER TABLE tblcommodityOHLC
ALTER COLUMN
    CC_CommodityContractID NUMERIC(18,0), 
    CM_CommodityID NUMERIC(18,0)

1
Was ist der wahrgenommene Vorteil, wenn Sie es auf einmal tun?
Tag, wenn

5
@onedaywhen - Damit SQL Server nur einmal die Tabelle durchläuft, um die erforderliche Validierung für den neuen Datentyp durchzuführen und / oder die geänderten Spalten im neuen Format zu schreiben.
Martin Smith

1
Kein großer Vorteil dann!
Tag, wenn

4
Gegenteil. Es wäre ein großer Vorteil, einen Änderungslauf in 2 statt 24 Stunden für mehrere Spalten auf großen Tischen durchzuführen.
Norbert Kardos

Antworten:


135

Das ist nicht möglich. Sie müssen dies einzeln tun.

Sie können eine temporäre Tabelle mit Ihren geänderten Spalten erstellen, die Daten kopieren, Ihre ursprüngliche Tabelle löschen und Ihre temporäre Tabelle in Ihren ursprünglichen Namen umbenennen.


5
+1, You will need to do this one by one.also, was ist die große Sache, verwenden Sie einfach mehrere ALTER TABLE ALTER COLUMNBefehle?
KM.

6
@KM Ein Problem ist, wenn Sie einen großen Tisch ändern. Jede Anweisung bedeutet einen neuen Scan, aber wenn Sie mehrere Spalten ändern könnten, hätte jede Änderung viel schneller sein können
erikkallen

@erikkallen, dann machen Sie wie SSMS-Tools normalerweise ihre Skripte: Erstellen Sie eine neue Tabelle und replizieren Sie FKs und Indizes usw., löschen Sie die Originaltabelle und benennen Sie dann die neue Tabelle um,
KM.

Das Löschen und Neuerstellen von Tabellen ist eine ziemlich intensive Operation. In SSMS ist es jetzt standardmäßig deaktiviert, wahrscheinlich aus gutem Grund.
Jocull

"Each statement means a new scan": Nicht unbedingt @erikkallen. In einigen Fällen ist die ALTER-Spalte eine einfache Metadatenänderung. Sie können gerne morgen an meinem Vortrag über " SQL Internals - Physical Table Structure under the hood, and implementation on real case scenarios" teilnehmen, um alles in der Praxis zu sehen :-)
Ronen Ariely

26

Es ist nicht möglich, mehrere ALTER COLUMNAktionen innerhalb einer einzelnen ALTER TABLEAnweisung auszuführen.

Siehe die ALTER TABLESyntax hier

Sie können mehrere ADDoder mehrere ausführen DROP COLUMN, aber nur eine ALTER COLUMN.


17

Wie andere geantwortet haben, benötigen Sie mehrere ALTER TABLEAnweisungen.
Versuchen Sie Folgendes:

ALTER TABLE tblcommodityOHLC alter column CC_CommodityContractID NUMERIC(18,0);
ALTER TABLE tblcommodityOHLC alter column CM_CommodityID NUMERIC(18,0);

12

Die folgende Lösung ist keine einzelne Anweisung zum Ändern mehrerer Spalten, aber ja, sie macht das Leben einfach:

  1. Generieren Sie das CREATESkript einer Tabelle .

  2. Ersetzen Sie CREATE TABLEdurch ALTER TABLE [TableName] ALTER COLUMNfür die erste Zeile

  3. Entfernen Sie unerwünschte Spalten aus der Liste.

  4. Ändern Sie die Spaltendatentypen nach Ihren Wünschen.

  5. Führen Sie ein Suchen und Ersetzen… wie folgt durch:

    1. Finden Sie : NULL,
    2. Ersetzen mit: NULL; ALTER TABLE [TableName] ALTER COLUMN
    3. Klicken Sie auf die Schaltfläche Ersetzen .
  6. Führen Sie das Skript aus.

Hoffe es spart viel Zeit :))


6

Wie viele andere bereits gesagt haben, müssen Sie mehrere ALTER COLUMNAnweisungen verwenden, eine für jede Spalte, die Sie ändern möchten.

Wenn Sie alle oder mehrere Spalten in Ihrer Tabelle auf denselben Datentyp ändern möchten (z. B. das Erweitern eines VARCHAR-Felds von 50 auf 100 Zeichen), können Sie alle Anweisungen mithilfe der folgenden Abfrage automatisch generieren. Diese Technik ist auch nützlich, wenn Sie dasselbe Zeichen in mehreren Feldern ersetzen möchten (z. B. \ t aus allen Spalten entfernen).

SELECT
     TABLE_CATALOG
    ,TABLE_SCHEMA
    ,TABLE_NAME
    ,COLUMN_NAME
    ,'ALTER TABLE ['+TABLE_SCHEMA+'].['+TABLE_NAME+'] ALTER COLUMN ['+COLUMN_NAME+'] VARCHAR(300)' as 'code'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'your_table' AND TABLE_SCHEMA = 'your_schema'

Dadurch wird ALTER TABLEfür jede Spalte eine Anweisung für Sie generiert .


1

Wenn Sie die Änderungen in Management Studio vornehmen und Skripte generieren, wird eine neue Tabelle erstellt und die alten Daten mit den geänderten Datentypen in diese eingefügt. Hier ist ein kleines Beispiel zum Ändern der Datentypen von zwei Spalten

/*
   12 August 201008:30:39
   User: 
   Server: CLPPRGRTEL01\TELSQLEXPRESS
   Database: Tracker_3
   Application: 
*/

/* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.tblDiary
    DROP CONSTRAINT FK_tblDiary_tblDiary_events
GO
ALTER TABLE dbo.tblDiary_events SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_tblDiary
    (
    Diary_ID int NOT NULL IDENTITY (1, 1),
    Date date NOT NULL,
    Diary_event_type_ID int NOT NULL,
    Notes varchar(MAX) NULL,
    Expected_call_volumes real NULL,
    Expected_duration real NULL,
    Skill_affected smallint NULL
    )  ON T3_Data_2
     TEXTIMAGE_ON T3_Data_2
GO
ALTER TABLE dbo.Tmp_tblDiary SET (LOCK_ESCALATION = TABLE)
GO
SET IDENTITY_INSERT dbo.Tmp_tblDiary ON
GO
IF EXISTS(SELECT * FROM dbo.tblDiary)
     EXEC('INSERT INTO dbo.Tmp_tblDiary (Diary_ID, Date, Diary_event_type_ID, Notes, Expected_call_volumes, Expected_duration, Skill_affected)
        SELECT Diary_ID, Date, Diary_event_type_ID, CONVERT(varchar(MAX), Notes), Expected_call_volumes, Expected_duration, CONVERT(smallint, Skill_affected) FROM dbo.tblDiary WITH (HOLDLOCK TABLOCKX)')
GO
SET IDENTITY_INSERT dbo.Tmp_tblDiary OFF
GO
DROP TABLE dbo.tblDiary
GO
EXECUTE sp_rename N'dbo.Tmp_tblDiary', N'tblDiary', 'OBJECT' 
GO
ALTER TABLE dbo.tblDiary ADD CONSTRAINT
    PK_tblDiary PRIMARY KEY NONCLUSTERED 
    (
    Diary_ID
    ) WITH( PAD_INDEX = OFF, FILLFACTOR = 86, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON T3_Data_2

GO
CREATE UNIQUE CLUSTERED INDEX tblDiary_ID ON dbo.tblDiary
    (
    Diary_ID
    ) WITH( PAD_INDEX = OFF, FILLFACTOR = 86, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON T3_Data_2
GO
CREATE NONCLUSTERED INDEX tblDiary_date ON dbo.tblDiary
    (
    Date
    ) WITH( PAD_INDEX = OFF, FILLFACTOR = 86, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON T3_Data_2
GO
ALTER TABLE dbo.tblDiary WITH NOCHECK ADD CONSTRAINT
    FK_tblDiary_tblDiary_events FOREIGN KEY
    (
    Diary_event_type_ID
    ) REFERENCES dbo.tblDiary_events
    (
    Diary_event_ID
    ) ON UPDATE  CASCADE 
     ON DELETE  CASCADE 

GO
COMMIT

1

Wenn Sie nicht alles selbst schreiben und alle Spalten auf denselben Datentyp ändern möchten, kann dies Folgendes vereinfachen:

select 'alter table tblcommodityOHLC alter column '+name+ 'NUMERIC(18,0);'
from syscolumns where id = object_id('tblcommodityOHLC ')

Sie können die Ausgabe als Abfrage kopieren und einfügen


0
select 'ALTER TABLE ' + OBJECT_NAME(o.object_id) + 
    ' ALTER COLUMN ' + c.name + ' DATETIME2 ' + 
    CASE WHEN c.is_nullable = 0 THEN 'NOT NULL' ELSE 'NULL' END
from sys.objects o
inner join sys.columns c on o.object_id = c.object_id
inner join sys.types t on c.system_type_id = t.system_type_id
where o.type='U'
and c.name = 'Timestamp'
and t.name = 'datetime'
order by OBJECT_NAME(o.object_id)

Mit freundlicher Genehmigung von Devio


0

Dank Evans Codebeispiel konnte ich es weiter modifizieren und spezifischer für Tabellen machen, die mit bestimmten Spaltennamen beginnen UND auch Besonderheiten für Einschränkungen behandeln. Ich habe diesen Code ausgeführt, dann die Spalte [CODE] kopiert und ohne Probleme ausgeführt.

USE [Table_Name]
GO
SELECT
     TABLE_CATALOG
    ,TABLE_SCHEMA
    ,TABLE_NAME
    ,COLUMN_NAME
    ,DATA_TYPE
    ,'ALTER TABLE ['+TABLE_SCHEMA+'].['+TABLE_NAME+'] DROP CONSTRAINT [DEFAULT_'+TABLE_NAME+'_'+COLUMN_NAME+']; 
ALTER TABLE  ['+TABLE_SCHEMA+'].['+TABLE_NAME+'] ALTER COLUMN ['+COLUMN_NAME+'] datetime2 (7) NOT NULL 
ALTER TABLE  ['+TABLE_SCHEMA+'].['+TABLE_NAME+'] ADD CONSTRAINT [DEFAULT_'+TABLE_NAME+'_'+COLUMN_NAME+'] DEFAULT (''3/6/2018 6:47:23 PM'') FOR ['+COLUMN_NAME+']; 
GO' AS '[CODE]'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME LIKE 'form_%' AND TABLE_SCHEMA = 'dbo'
 AND (COLUMN_NAME = 'FormInserted' OR COLUMN_NAME = 'FormUpdated')
 AND DATA_TYPE = 'datetime'

0
-- create temp table 
CREATE TABLE temp_table_alter
(
column_name varchar(255)    
);

-- insert those coulmns in temp table for which we nee to alter size of columns 
INSERT INTO temp_table_alter (column_name) VALUES ('colm1');
INSERT INTO temp_table_alter (column_name) VALUES ('colm2');
INSERT INTO temp_table_alter (column_name) VALUES ('colm3');
INSERT INTO temp_table_alter (column_name) VALUES ('colm4');

DECLARE @col_name_var varchar(255);
DECLARE alter_table_cursor CURSOR FOR
select column_name from temp_table_alter ;

OPEN alter_table_cursor
FETCH NEXT FROM alter_table_cursor INTO @col_name_var
WHILE @@FETCH_STATUS = 0
 BEGIN

 PRINT('ALTER COLUMN ' + @col_name_var);
 EXEC ('ALTER TABLE Original-table  ALTER COLUMN ['+ @col_name_var + '] DECIMAL(11,2);')

 FETCH NEXT FROM alter_table_cursor INTO @col_name_var
 END

CLOSE alter_table_cursor
DEALLOCATE alter_table_cursor

-- at the end drop temp table
drop table temp_table_alter;

KEINE gute Lösung. Cursor und Loops sollten unbedingt vermieden werden !!!
Ray K.

1
Nicht wahr, Ray. Cursor und Schleifen eignen sich gut für bestimmte DDL-Aufgaben und andere notwendigerweise RBR-Aufgaben.
Jeff Moden

-3

Wir können mehrere Spalten in einer einzigen Abfrage wie folgt ändern:

ALTER TABLE `tblcommodityOHLC`
    CHANGE COLUMN `updated_on` `updated_on` DATETIME NULL DEFAULT NULL AFTER `updated_by`,
    CHANGE COLUMN `delivery_datetime` `delivery_datetime` DATETIME NULL DEFAULT CURRENT_TIMESTAMP AFTER `delivery_status`;

Geben Sie die Abfragen einfach durch Komma getrennt an.


4
Ich denke das ist MySql? Die Frage war für SQL Server, und dies funktioniert nicht in SQL Server
Tjipke

-4

Setzen Sie die ALTER COLUMNAnweisung in eine Klammer, es sollte funktionieren.

ALTER TABLE tblcommodityOHLC alter ( column  
CC_CommodityContractID NUMERIC(18,0), 
CM_CommodityID NUMERIC(18,0) )

-4

Wenn ich Ihre Frage richtig verstanden habe, können Sie mithilfe der unten genannten Abfrage mehrere Spalten in eine Tabelle einfügen.

Abfrage:

Alter table tablename add (column1 dataype, column2 datatype);

4
Das OP fragte nach der ALTER-Spalte, nicht nach ADD.
DR
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.