Jak zmienić wiele kolumn jednocześnie w SQL Server

143

Potrzebuję ALTERtypów danych z kilku kolumn w tabeli.

W przypadku pojedynczej kolumny działa dobrze:

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

Ale jak zmienić wiele kolumn w jednej instrukcji? Nie działa:

ALTER TABLE tblcommodityOHLC
ALTER COLUMN
    CC_CommodityContractID NUMERIC(18,0), 
    CM_CommodityID NUMERIC(18,0)
D.mahesh
źródło
1
Jaka jest postrzegana korzyść zrobienia tego za jednym razem?
kiedy
5
@onedaywhen - aby SQL Server wykonał tylko jedno przejście przez tabelę, aby wykonać niezbędne sprawdzenie poprawności względem nowego typu danych i / lub wypisać zmienione kolumny w nowym formacie.
Martin Smith
1
Nie ma to wielkiej korzyści!
kiedy
4
Przeciwnie. Byłoby wielką zaletą, gdyby zmiana była uruchamiana w 2 godziny zamiast 24 w przypadku wielu kolumn przy dużych stołach.
Norbert Kardos

Odpowiedzi:

135

To jest niemożliwe. Będziesz musiał to zrobić jeden po drugim.

Możesz utworzyć tabelę tymczasową ze zmodyfikowanymi kolumnami, skopiować dane, upuścić oryginalną tabelę i zmienić nazwę tabeli tymczasowej na oryginalną.

Neil Knight
źródło
5
+1, You will need to do this one by one.więc o co chodzi, po prostu użyj wielu ALTER TABLE ALTER COLUMNpoleceń?
KM.
6
@KM Jednym z problemów jest zmiana dużego stołu. Każde stwierdzenie oznacza nowe skanowanie, ale gdybyś mógł zmienić wiele kolumn, wszystkie zmiany mogłyby być znacznie szybsze
erikkallen
@erikkallen, a następnie postępuj tak, jak narzędzia SSMS, zwykle generują swoje skrypty: utwórz nową tabelę i replikuj FK i indeksy itp., usuń oryginalną tabelę, a następnie zmień nazwę nowej tabeli,
KM.
Usuwanie i odtwarzanie tabel to dość intensywna operacja. Jest teraz domyślnie wyłączony w SSMS i prawdopodobnie nie bez powodu.
wesoły
"Each statement means a new scan": Niekoniecznie @erikkallen. W niektórych przypadkach ALTER kolumna to prosta zmiana metadanych. Zapraszam na jutrzejszy wykład na temat „ SQL Internals - Physical Table Structure under the hood, and implementation on real case scenarios”, aby zobaczyć to wszystko w praktyce :-)
Ronen Ariely
26

Wykonywanie wielu ALTER COLUMNczynności w ramach jednej ALTER TABLEinstrukcji nie jest możliwe.

Zobacz ALTER TABLEskładnię tutaj

Możesz zrobić wiele ADDlub wiele DROP COLUMN, ale tylko jeden ALTER COLUMN.

Fernando Torres
źródło
17

Jak odpowiedzieli inni, potrzebujesz wielu ALTER TABLEinstrukcji.
Spróbuj wykonać następujące czynności:

ALTER TABLE tblcommodityOHLC alter column CC_CommodityContractID NUMERIC(18,0);
ALTER TABLE tblcommodityOHLC alter column CM_CommodityID NUMERIC(18,0);
Ray K.
źródło
12

Poniższe rozwiązanie nie jest pojedynczym poleceniem zmiany wielu kolumn, ale tak, ułatwia życie:

  1. Wygeneruj CREATEskrypt tabeli .

  2. Wymień CREATE TABLEsię ALTER TABLE [TableName] ALTER COLUMNna pierwszej linii

  3. Usuń niechciane kolumny z listy.

  4. Zmień typy danych kolumn, jak chcesz.

  5. Wykonaj Znajdź i zamień… w następujący sposób:

    1. Znajdź: NULL,
    2. Zamienić: NULL; ALTER TABLE [TableName] ALTER COLUMN
    3. Kliknij przycisk Zamień .
  6. Uruchom skrypt.

Mam nadzieję, że zaoszczędzi to dużo czasu :))

Pritam
źródło
6

Jak powiedziało wielu innych, będziesz musiał użyć wielu ALTER COLUMNinstrukcji, po jednej dla każdej kolumny, którą chcesz zmodyfikować.

Jeśli chcesz zmodyfikować wszystkie lub kilka kolumn w swojej tabeli na ten sam typ danych (np. Rozszerzenie pola VARCHAR z 50 do 100 znaków), możesz automatycznie wygenerować wszystkie instrukcje, korzystając z poniższego zapytania. Ta technika jest również przydatna, jeśli chcesz zamienić ten sam znak w wielu polach (na przykład usunąć \ t ze wszystkich kolumn).

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'

Spowoduje to wygenerowanie ALTER TABLEzestawienia dla każdej kolumny.

Evan
źródło
1

Jeśli dokonasz zmian w Management Studio i wygenerujesz skrypty, utworzy nową tabelę i wstawi do niej stare dane ze zmienionymi typami danych. Oto mały przykład zmiany typów danych w dwóch kolumnach

/*
   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
Kevin Ross
źródło
1

Jeśli nie chcesz pisać wszystkiego samodzielnie i zmienić wszystkie kolumny na ten sam typ danych, może to ułatwić:

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

Możesz skopiować i wkleić dane wyjściowe jako zapytanie

Rishi
źródło
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)

dzięki uprzejmości devio

Spyder
źródło
0

Dzięki przykładowemu kodowi Evana byłem w stanie go bardziej zmodyfikować i uzyskać bardziej specyficzne dla tabel zaczynających się od, określonych nazw kolumn ORAZ również obsługiwać specyfikę ograniczeń. Uruchomiłem ten kod, a następnie skopiowałem kolumnę [CODE] i wykonałem go bez problemu.

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'
Brenden Kehren
źródło
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;
Aurangzeb khan
źródło
NIE jest to dobre rozwiązanie. Kursorów i pętli należy unikać za wszelką cenę !!!
Ray K.
1
Nieprawda, Ray. Kursory i pętle są odpowiednie dla niektórych zadań DDL i innych zadań RBR.
Jeff Moden,
-3

Możemy zmienić wiele kolumn w jednym zapytaniu, na przykład:

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`;

Po prostu podaj zapytania rozdzielone przecinkami.

Muhammed Shihabudeen Labba A
źródło
4
Myślę, że to MySql? Pytanie dotyczyło SQL Server, a to nie działa na serwerze sql
Tjipke
-4

Umieść ALTER COLUMNinstrukcję w nawiasie, powinno działać.

ALTER TABLE tblcommodityOHLC alter ( column  
CC_CommodityContractID NUMERIC(18,0), 
CM_CommodityID NUMERIC(18,0) )
Jai Prakash Rai
źródło
-4

Jeśli dobrze zrozumiałem twoje pytanie, możesz dodać wiele kolumn w tabeli za pomocą poniższego zapytania.

Pytanie:

Alter table tablename add (column1 dataype, column2 datatype);
Virendra Gawade
źródło
4
OP zapytał o kolumnę ALTER, a nie ADD.
DR