Cách THAY ĐỔI nhiều cột cùng một lúc trong SQL Server


143

Tôi cần ALTERcác kiểu dữ liệu của một số cột trong một bảng.

Đối với một cột duy nhất, các hoạt động sau đây hoạt động tốt:

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

Nhưng làm cách nào để thay đổi nhiều cột trong một câu lệnh? Những điều sau đây không hoạt động:

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

1
Lợi thế nhận thức để làm điều đó trong một lần là gì?
onedaywhen

5
@encedaywhen - Vì vậy, SQL Server sẽ chỉ thực hiện một lần đi qua bảng để thực hiện bất kỳ xác nhận cần thiết nào đối với kiểu dữ liệu mới và / hoặc viết ra các cột đã thay đổi trong định dạng mới.
Martin Smith

1
Không có lợi thế lớn rồi!
onedaywhen

4
Trái ngược. Sẽ là một lợi thế lớn khi có một thay đổi chạy trong 2 giờ thay vì 24 cho nhiều cột trên các bảng lớn.
Norbert Kardos

Câu trả lời:


135

Điều này là không thể. Bạn sẽ cần phải làm điều này từng cái một.

Bạn có thể tạo Bảng tạm thời với các cột đã sửa đổi, sao chép dữ liệu qua, thả bảng gốc và đổi tên Bảng tạm thời thành tên ban đầu của bạn.


5
+1, You will need to do this one by one.vì vậy, vấn đề lớn là gì, chỉ cần sử dụng nhiều ALTER TABLE ALTER COLUMNlệnh?
KM.

6
@KM Một vấn đề là nếu bạn đang thay đổi một bảng lớn. Mỗi câu lệnh có nghĩa là một lần quét mới nhưng nếu bạn có thể thay đổi nhiều cột, thì mọi thay đổi có thể nhanh hơn nhiều
erikkallen

@erikkallen, sau đó làm như các công cụ SSMS thường tạo tập lệnh của chúng: tạo bảng mới và sao chép FK và chỉ mục, v.v., bỏ bảng gốc rồi đổi tên bảng mới,
KM.

Thả và tạo lại các bảng là một hoạt động khá chuyên sâu. Hiện tại, nó bị vô hiệu hóa trong SSMS và có lẽ vì lý do chính đáng.
vui vẻ

"Each statement means a new scan": Không nhất thiết là @erikkallen. Trong một số trường hợp, cột ALTER là một thay đổi siêu dữ liệu đơn giản. Bạn được chào đón tham gia bài giảng của tôi vào ngày mai về " SQL Internals - Physical Table Structure under the hood, and implementation on real case scenarios" để thấy tất cả trong thực tế :-)
Ronen Ariely

26

Thực hiện nhiều ALTER COLUMNhành động bên trong một ALTER TABLEtuyên bố là không thể.

Xem ALTER TABLEcú pháp tại đây

Bạn có thể làm nhiều ADDhoặc nhiều DROP COLUMN, nhưng chỉ một ALTER COLUMN.


17

Như những người khác đã trả lời, bạn cần nhiều ALTER TABLEtuyên bố.
Hãy thử làm theo:

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

12

Giải pháp sau đây không phải là một tuyên bố duy nhất để thay đổi nhiều cột, nhưng vâng, nó làm cho cuộc sống đơn giản:

  1. Tạo CREATEtập lệnh của bảng .

  2. Thay thế CREATE TABLEbằng ALTER TABLE [TableName] ALTER COLUMNcho dòng đầu tiên

  3. Xóa các cột không mong muốn khỏi danh sách.

  4. Thay đổi các kiểu dữ liệu cột như bạn muốn.

  5. Thực hiện Tìm và Thay thế trên mạng như sau:

    1. Tìm thấy: NULL ,
    2. Thay thế bằng: NULL; ALTER TABLE [TableName] ALTER COLUMN
    3. Nhấn nút Thay thế .
  6. Chạy kịch bản.

Hy vọng nó sẽ tiết kiệm được nhiều thời gian :))


6

Như nhiều người khác đã nói, bạn sẽ cần sử dụng nhiều ALTER COLUMN câu lệnh, một câu lệnh cho mỗi cột bạn muốn sửa đổi.

Nếu bạn muốn sửa đổi tất cả hoặc một số cột trong bảng của mình thành cùng một kiểu dữ liệu (chẳng hạn như mở rộng trường VARCHAR từ 50 đến 100 ký tự), bạn có thể tự động tạo tất cả các câu lệnh bằng truy vấn bên dưới. Kỹ thuật này cũng hữu ích nếu bạn muốn thay thế cùng một ký tự trong nhiều trường (chẳng hạn như xóa \ t khỏi tất cả các cột).

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'

Điều này tạo ra một ALTER TABLEtuyên bố cho mỗi cột cho bạn.


1

Nếu bạn thực hiện các thay đổi trong phòng quản lý và tạo tập lệnh, nó sẽ tạo một bảng mới và chèn dữ liệu cũ vào đó với các kiểu dữ liệu đã thay đổi. Dưới đây là một ví dụ nhỏ thay đổi loại dữ liệu của hai cột

/*
   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

Nếu bạn không muốn tự mình viết toàn bộ và thay đổi tất cả các cột thành cùng một kiểu dữ liệu, điều này có thể giúp bạn dễ dàng hơn:

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

Bạn có thể sao chép và dán đầu ra như truy vấn của bạn


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)

lịch sự của devio


0

Nhờ mẫu mã của Evan, tôi đã có thể sửa đổi nó nhiều hơn và làm cho nó cụ thể hơn với các bảng bắt đầu bằng, tên cột cụ thể VÀ xử lý các chi tiết cụ thể cho các ràng buộc. Tôi đã chạy mã đó và sau đó sao chép cột [CODE] và thực thi nó mà không gặp vấn đề gì.

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;

KHÔNG phải là một giải pháp tốt. Nên tránh các con trỏ và vòng lặp bằng TẤT CẢ !!!
Ray K.

1
Không đúng, Ray. Các con trỏ và vòng lặp đều ổn đối với các tác vụ DDL nhất định và các tác vụ RBR nhất thiết khác.
Jeff Moden

-3

Chúng tôi có thể thay đổi nhiều cột trong một truy vấn như thế này:

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

Chỉ cần cung cấp các truy vấn như dấu phẩy được phân tách.


4
Tôi nghĩ đây là MySql? Câu hỏi đặt ra cho SQL Server và điều này không hoạt động trong máy chủ sql
Tjipke 26/07/18

-4

Đặt ALTER COLUMNtuyên bố trong một khung, nó sẽ hoạt động.

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

-4

Nếu tôi hiểu chính xác câu hỏi của bạn, bạn có thể thêm nhiều cột trong một bảng bằng cách sử dụng truy vấn được đề cập bên dưới.

Truy vấn:

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

4
OP hỏi về cột ALTER, không phải THÊM.
DR
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.