SQL Serverで複数の列を一度に変更する方法


143

ALTERテーブルのいくつかの列のデータ型が必要です。

単一の列の場合、以下は正常に機能します。

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

しかし、1つのステートメントで複数の列を変更するにはどうすればよいですか?以下は機能しません。

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

1
一度にそれを行うことの認識されている利点は何ですか?
10

5
@onedaywhen-SQL Serverがテーブルを1回通過するだけで、新しいデータ型に対して必要な検証を実行したり、変更された列を新しい形式で書き込んだりします。
Martin Smith

1
そのとき大きな利点はありません!
2015

4
逆です。大きなテーブルの複数の列に対して、alterを24時間ではなく2時間で実行することは大きな利点です。
Norbert Kardos、2018

回答:


135

これは不可能です。これは1つずつ行う必要があります。

変更した列を含む一時テーブルを作成し、データをコピーして、元のテーブルをドロップし、一時テーブルの名前を元の名前に変更できます。


5
+1、You will need to do this one by one.それで、大したことはALTER TABLE ALTER COLUMN何ですか、複数のコマンドを使用するだけですか?
和基。

6
@KM 1つの問題は、大きなテーブルを変更する場合です。各ステートメントは新しいスキャンを意味しますが、複数の列を変更できれば、すべての変更がはるかに速くなる可能性があります
erikkallen

@erikkallenの場合、SSMSツールと同様に通常スクリプトを生成します。新しいテーブルを作成し、FKとインデックスなどをレプリケートし、元のテーブルを削除してから、新しいテーブルの名前を変更します
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

26

ALTER COLUMN1つのALTER TABLEステートメント内で複数のアクションを実行することはできません。

ALTER TABLE構文はこちらをご覧ください

複数ADDまたは複数行うことができますDROP COLUMNが、1つだけALTER COLUMNです。


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 TABLEALTER TABLE [TableName] ALTER COLUMN、最初の行のために

  3. リストから不要な列を削除します。

  4. 必要に応じて列のデータ型を変更します。

  5. 次のように検索と置換を実行します。

    1. 検索:NULL
    2. と置換する: NULL; ALTER TABLE [TableName] ALTER COLUMN
    3. ヒット置き換えボタンを。
  6. スクリプトを実行します。

それが多くの時間を節約することを願っています:))


6

他の多くの人が言ったように、ALTER COLUMN変更する列ごとに1つずつ、複数のステートメントを使用する必要があります。

テーブルのすべてまたはいくつかの列を同じデータ型に変更する場合(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

Management Studioで変更を行い、スクリプトを生成すると、新しいテーブルが作成され、変更されたデータタイプで古いデータがそのテーブルに挿入されます。2つの列のデータ型を変更する小さな例を次に示します

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

devioの好意による


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;

良い解決策ではありません。カーソルとループは絶対に避けてください!!!
レイK.

1
そうではない、レイ。カーソルとループは、特定のDDLタスクおよびその他の必然的なRBRタスクに適しています。
Jeff Moden 2017年

-3

次のように、1つのクエリで複数の列を変更できます。

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 Serverでは機能しません
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は、ADDではなくALTER列について尋ねました。
DR
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.