Как ИЗМЕНИТЬ сразу несколько столбцов в SQL Server


147

Мне нужны 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
Каковы предполагаемые преимущества выполнения этого за один раз?
однажды,

5
@onedaywhen - чтобы SQL Server только один раз проходил через таблицу, чтобы выполнить любую необходимую проверку на соответствие новому типу данных и / или записать измененные столбцы в новом формате.
Мартин Смит

1
Тогда нет большого преимущества!
однажды, когда

4
Напротив. Было бы большим преимуществом выполнить изменение за 2 часа вместо 24 для нескольких столбцов в больших таблицах.
Норберт Кардос

Ответы:


140

Это невозможно . Вам нужно будет делать это по одному. Ты мог бы:

  1. Создайте временную таблицу с измененными столбцами в
  2. Скопируйте данные через
  3. Отбросьте исходный стол (дважды проверьте перед этим!)
  4. Переименуйте свою временную таблицу в свое исходное имя

5
+1, You will need to do this one by one.так что в этом такого, просто использовать несколько ALTER TABLE ALTER COLUMNкоманд?
КМ.

7
@KM Одна проблема - если вы изменяете большую таблицу. Каждое утверждение означает новое сканирование, но если бы вы могли изменить несколько столбцов, все изменения могли бы быть намного быстрее,
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", чтобы увидеть все это на практике :-)
Ронен

27

Выполнение нескольких ALTER COLUMNдействий внутри одного ALTER TABLEоператора невозможно.

Смотрите ALTER TABLEсинтаксис здесь

Вы можете делать несколько ADDили несколько DROP COLUMN, но только один 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 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

Если вы вносите изменения в Management Studio и генерируете сценарии, она создает новую таблицу и вставляет в нее старые данные с измененными типами данных. Вот небольшой пример изменения типа данных двух столбцов

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

Благодаря образцу кода Эвана я смог изменить его больше и сделать его более конкретным для таблиц, начинающихся с определенных имен столбцов, И также обрабатывать специфические особенности для ограничений. Я запустил этот код, а затем скопировал столбец [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.
Джефф Моден

-3

Поместите ALTER COLUMNоператор в скобки, он должен работать.

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

-3

Если я правильно понял ваш вопрос, вы можете добавить несколько столбцов в таблицу, используя указанный ниже запрос.

Запрос:

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

4
OP спросил о столбце ALTER, а не ADD.
DR

-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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.