Como alterar várias colunas ao mesmo tempo no SQL Server

143

Eu preciso ALTERdos tipos de dados de várias colunas em uma tabela.

Para uma única coluna, o seguinte funciona bem:

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

Mas como altero várias colunas em uma instrução? O seguinte não funciona:

ALTER TABLE tblcommodityOHLC
ALTER COLUMN
    CC_CommodityContractID NUMERIC(18,0), 
    CM_CommodityID NUMERIC(18,0)
D.mahesh
fonte
1
Qual é a vantagem percebida de fazê-lo de uma só vez?
precisa saber é o seguinte
5
@onedaywhen - Para que o SQL Server faça uma passagem pela tabela para fazer a validação necessária contra o novo tipo de dados e / ou gravar as colunas alteradas no novo formato.
Martin Smith
1
Nenhuma grande vantagem então!
precisa saber é o seguinte
4
Contrário. Seria uma grande vantagem ter uma alteração executada em 2 horas, em vez de 24, para várias colunas em grandes tabelas.
Norbert Kardos

Respostas:

135

Isso não é possível. Você precisará fazer isso um por um.

Você pode criar uma tabela temporária com suas colunas modificadas, copiar os dados, soltar sua tabela original e renomear sua tabela temporária para seu nome original.

Neil Knight
fonte
5
+1, You will need to do this one by one.então, qual é o problema, basta usar vários ALTER TABLE ALTER COLUMNcomandos?
KM.
6
@KM Um problema é se você está alterando uma mesa grande. Cada declaração significa uma nova verificação, mas se você pode alterar várias colunas, toda alteração poderia ter sido muito mais rápido
erikkallen
@erikkallen, então, como as ferramentas SSMS, geralmente geram seus scripts: crie uma nova tabela e replique FKs e índices, etc, descarte a tabela original e renomeie a nova tabela,
KM.
Largar e recriar tabelas é uma operação bastante intensiva. Ele está desativado por padrão no SSMS agora e provavelmente por um bom motivo.
jocull
"Each statement means a new scan": Não necessariamente @erikkallen. Em alguns casos, a coluna ALTER é uma simples alteração de metadados. Você está convidado a participar da minha palestra amanhã sobre " SQL Internals - Physical Table Structure under the hood, and implementation on real case scenarios" para ver tudo isso de forma prática :-)
Ronen Ariely
26

Não é possível executar várias ALTER COLUMNações em uma única ALTER TABLEinstrução.

Veja a ALTER TABLEsintaxe aqui

Você pode fazer múltiplos ADDou múltiplos DROP COLUMN, mas apenas um ALTER COLUMN.

Fernando Torres
fonte
17

Como outras pessoas responderam, você precisa de várias ALTER TABLEdeclarações.
Tente o seguinte:

ALTER TABLE tblcommodityOHLC alter column CC_CommodityContractID NUMERIC(18,0);
ALTER TABLE tblcommodityOHLC alter column CM_CommodityID NUMERIC(18,0);
Ray K.
fonte
12

A solução a seguir não é uma declaração única para alterar várias colunas, mas sim, simplifica a vida:

  1. Gere o CREATEscript de uma tabela .

  2. Substitua CREATE TABLEpor ALTER TABLE [TableName] ALTER COLUMNpara primeira linha

  3. Remova colunas indesejadas da lista.

  4. Altere os tipos de dados das colunas como desejar.

  5. Realize uma localização e substituição… da seguinte maneira:

    1. Localizar: NULL,
    2. Substituir com: NULL; ALTER TABLE [TableName] ALTER COLUMN
    3. Clique no botão Substituir .
  6. Execute o script.

Espero que ele economize muito tempo :))

Pritam
fonte
6

Como muitos outros disseram, você precisará usar vários ALTER COLUMN instruções, uma para cada coluna que deseja modificar.

Se você deseja modificar todas ou várias das colunas da sua tabela para o mesmo tipo de dados (como expandir um campo VARCHAR de 50 para 100 caracteres), é possível gerar todas as instruções automaticamente usando a consulta abaixo. Essa técnica também é útil se você deseja substituir o mesmo caractere em vários campos (como remover \ t de todas as colunas).

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'

Isso gera uma ALTER TABLEdeclaração para cada coluna para você.

Evan
fonte
1

Se você fizer as alterações no Management Studio e gerar scripts, ela cria uma nova tabela e insere os dados antigos nela com os tipos de dados alterados. Aqui está um pequeno exemplo de alteração dos tipos de dados de duas colunas

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

Se você não quiser escrever a coisa toda e alterar todas as colunas para o mesmo tipo de dados, isso poderá facilitar:

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

Você pode copiar e colar a saída como sua consulta

Rishi
fonte
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)

cortesia de devio

Spyder
fonte
0

Graças ao exemplo de código de Evan, eu pude modificá-lo mais e especificá-lo para tabelas que começavam com nomes de colunas específicos E lidamos com detalhes de restrições também. Executei esse código e copiei a coluna [CODE] e a executei sem problemas.

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
fonte
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
fonte
NÃO é uma boa solução. Cursores e loops devem ser evitados a todo custo !!!
Ray K.
1
Não é verdade, Ray. Cursores e loops são adequados para determinadas tarefas DDL e outras tarefas necessariamente RBR.
precisa
-3

Podemos alterar várias colunas em uma única consulta como esta:

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

Basta fornecer as consultas como separadas por vírgula.

Muhammed Shihabudeen Labba A
fonte
4
Eu acho que isso é MySql? A pergunta era para o SQL Server, e isso não funciona no sql server
Tjipke
-4

Coloque a ALTER COLUMNdeclaração dentro de um suporte, ele deve funcionar.

ALTER TABLE tblcommodityOHLC alter ( column  
CC_CommodityContractID NUMERIC(18,0), 
CM_CommodityID NUMERIC(18,0) )
Jai Prakash Rai
fonte
-4

Se entendi sua pergunta corretamente, você pode adicionar várias colunas em uma tabela usando a consulta mencionada abaixo.

Inquerir:

Alter table tablename add (column1 dataype, column2 datatype);
Virendra Gawade
fonte
4
O OP perguntou sobre a coluna ALTER, não ADD.
DR