วิธีการแก้ไขหลายคอลัมน์พร้อมกันใน SQL Server


143

ฉันต้องการALTERชนิดข้อมูลของหลายคอลัมน์ในตาราง

สำหรับคอลัมน์เดียวต่อไปนี้ใช้งานได้ดี:

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

แต่ฉันจะแก้ไขหลายคอลัมน์ในคำสั่งเดียวได้อย่างไร ต่อไปนี้ใช้ไม่ได้:

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

1
อะไรคือข้อได้เปรียบที่รับรู้สำหรับการทำในครั้งเดียว?
oneday เมื่อ

5
@onedaywhen - ดังนั้น SQL Server จะผ่านไปหนึ่งตารางเพื่อทำการตรวจสอบที่จำเป็นกับประเภทข้อมูลใหม่และ / หรือเขียนคอลัมน์ที่เปลี่ยนแปลงในรูปแบบใหม่
Martin Smith

1
ไม่มีข้อได้เปรียบที่ยอดเยี่ยม!
oneday เมื่อ

4
ตรงกันข้าม มันจะเป็นข้อได้เปรียบอย่างยิ่งที่จะมีการเปลี่ยนแปลงใน 2 ชั่วโมงแทนที่จะเป็น 24 สำหรับคอลัมน์หลาย ๆ คอลัมน์ในตารางขนาดใหญ่
Norbert Kardos

คำตอบ:


135

สิ่งนี้เป็นไปไม่ได้ คุณจะต้องทำสิ่งนี้ทีละอย่าง

คุณสามารถสร้างตารางชั่วคราวโดยใช้คอลัมน์ที่มีการปรับเปลี่ยนของคุณในคัดลอกข้อมูลข้ามวางตารางเดิมของคุณและเปลี่ยนชื่อตารางชั่วคราวเป็นชื่อเดิมของคุณ


5
+1 You will need to do this one by one.ดังนั้นเรื่องใหญ่ใช้ALTER TABLE ALTER COLUMNคำสั่งได้หลายคำ?
กม.

6
@KM ปัญหาหนึ่งคือถ้าคุณกำลังเปลี่ยนแปลงตารางขนาดใหญ่ แต่ละคำที่หมายถึงการสแกนใหม่ แต่ถ้าคุณสามารถปรับเปลี่ยนหลายคอลัมน์เปลี่ยนแปลงทั้งหมดจะได้รับเร็วมาก
erikkallen

@erikkallen จากนั้นทำเช่นเดียวกับเครื่องมือ SSMS มักจะสร้างสคริปต์ของพวกเขา: สร้างตารางใหม่และทำซ้ำ FKs และดัชนี ฯลฯ วางตารางต้นฉบับแล้วเปลี่ยนชื่อตารางใหม่
KM

การดร็อปและสร้างตารางซ้ำเป็นการดำเนินการที่ค่อนข้างเข้มงวด มันถูกปิดใช้งานโดยค่าเริ่มต้นใน SSMS ในตอนนี้และอาจเป็นไปได้ด้วยเหตุผล
jocull

"Each statement means a new scan": ไม่จำเป็นต้องเป็น @erikkallen ในบางกรณีคอลัมน์ ALTER เป็นการเปลี่ยนแปลงข้อมูลเมตาอย่างง่าย คุณสามารถเข้าร่วมการบรรยายของฉันในวันพรุ่งนี้เกี่ยวกับ " SQL Internals - Physical Table Structure under the hood, and implementation on real case scenarios" เพื่อดูทั้งหมดในทางปฏิบัติ :-)
Ronen Ariely


17

ตามที่คนอื่น ๆ ตอบคุณต้องมีหลายALTER TABLEงบ
ลองต่อไปนี้:

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

12

โซลูชันต่อไปนี้ไม่ใช่คำสั่งเดียวสำหรับการแก้ไขหลายคอลัมน์ แต่ใช่มันทำให้ชีวิตง่ายขึ้น:

  1. สร้างCREATEสคริปต์ของตาราง

  2. แทนที่CREATE TABLEด้วยALTER TABLE [TableName] ALTER COLUMNสำหรับบรรทัดแรก

  3. ลบคอลัมน์ที่ไม่ต้องการออกจากรายการ

  4. เปลี่ยนชนิดข้อมูลคอลัมน์ตามที่คุณต้องการ

  5. ดำเนินการค้นหาและแทนที่ ...ดังนี้:

    1. ค้นหา: NULL,
    2. แทนที่ด้วย: NULL; ALTER TABLE [TableName] ALTER COLUMN
    3. กดปุ่มแทนที่
  6. เรียกใช้สคริปต์

หวังว่ามันจะประหยัดเวลาได้มาก :))


6

ดังที่คนอื่น ๆ พูดไว้คุณจะต้องใช้หลาย ๆALTER COLUMNคำสั่งหนึ่งคำสำหรับแต่ละคอลัมน์ที่คุณต้องการแก้ไข

หากคุณต้องการแก้ไขคอลัมน์ทั้งหมดหรือหลายคอลัมน์ในตารางของคุณเป็นประเภทข้อมูลเดียวกัน (เช่นการขยายเขตข้อมูล VARCHAR จาก 50 เป็น 100 ตัวอักษร) คุณสามารถสร้างคำสั่งทั้งหมดโดยอัตโนมัติโดยใช้แบบสอบถามด้านล่าง เทคนิคนี้ยังมีประโยชน์หากคุณต้องการแทนที่อักขระเดียวกันในหลาย ๆ ฟิลด์ (เช่นลบ \ 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'

สิ่งนี้สร้างALTER TABLEคำสั่งสำหรับแต่ละคอลัมน์สำหรับคุณ


1

หากคุณทำการเปลี่ยนแปลงในสตูดิโอการจัดการและสร้างสคริปต์มันจะสร้างตารางใหม่และแทรกข้อมูลเก่าเข้าไปในประเภทข้อมูลที่เปลี่ยนแปลง นี่คือตัวอย่างเล็ก ๆ ที่เปลี่ยนประเภทข้อมูลของสองคอลัมน์

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

หากคุณไม่ต้องการเขียนสิ่งทั้งหมดด้วยตัวเองและเปลี่ยนคอลัมน์ทั้งหมดเป็นประเภทข้อมูลเดียวกันสิ่งนี้จะทำให้ง่ายขึ้น:

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

คุณสามารถคัดลอกและวางผลลัพธ์เป็นแบบสอบถามของคุณ


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)

มารยาทของดีโว


0

ขอบคุณตัวอย่างโค้ดของ Evan ทำให้ฉันสามารถแก้ไขเพิ่มเติมและทำให้เจาะจงมากขึ้นสำหรับตารางที่เริ่มต้นด้วยชื่อคอลัมน์เฉพาะและจัดการข้อ จำกัด เฉพาะสำหรับข้อ จำกัด เช่นกัน ฉันรันโค้ดนั้นแล้วคัดลอกคอลัมน์ [CODE] และดำเนินการโดยไม่มีปัญหา

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;

ไม่ใช่ทางออกที่ดี เคอร์เซอร์และลูปควรหลีกเลี่ยงค่าใช้จ่ายทั้งหมด !!!
เรย์เค

1
ไม่จริงเรย์ เคอร์เซอร์และลูปนั้นใช้ได้สำหรับงาน DDL บางงานและงาน RBR อื่น ๆ ที่จำเป็น
Jeff Moden

-3

เราสามารถเปลี่ยนหลายคอลัมน์ในแบบสอบถามเดียวเช่นนี้:

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

เพียงแค่ให้คำสืบค้นที่คั่นด้วยเครื่องหมายจุลภาค


4
ฉันคิดว่านี่คือ MySql? คำถามคือสำหรับ SQL Server และสิ่งนี้ไม่สามารถใช้งานได้ในเซิร์ฟเวอร์ sql
Tjipke

-4

ใส่ALTER COLUMNคำสั่งในวงเล็บมันควรจะทำงาน

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

-4

หากฉันเข้าใจคำถามของคุณถูกต้องคุณสามารถเพิ่มหลายคอลัมน์ในตารางโดยใช้แบบสอบถามที่กล่าวถึงด้านล่าง

ค้นหา:

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

4
OP ถามเกี่ยวกับคอลัมน์ ALTER ไม่ใช่ ADD
DR
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.