Come modificare più colonne contemporaneamente in SQL Server


143

Ho bisogno ALTERdei tipi di dati di più colonne in una tabella.

Per una singola colonna, funziona come segue:

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

Ma come posso modificare più colonne in un'unica istruzione? Quanto segue non funziona:

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

1
Qual è il vantaggio percepito per farlo in una volta sola?
Onedayquando il

5
@onedaywhen - In modo che SQL Server effettui solo un passaggio attraverso la tabella per eseguire tutte le convalide necessarie sul nuovo tipo di dati e / o scrivere le colonne modificate nel nuovo formato.
Martin Smith,

1
Nessun grande vantaggio quindi!
giorno

4
Contrario. Sarebbe un grande vantaggio avere una corsa alternata in 2 ore anziché 24 per più colonne su grandi tavoli.
Norbert Kardos,

Risposte:


135

Non è possibile. Dovrai farlo uno per uno.

È possibile creare una tabella temporanea con le colonne modificate, copiare i dati, eliminare la tabella originale e rinominare la tabella temporanea con il nome originale.


5
+1, You will need to do this one by one.quindi, qual è il grosso problema, basta usare più ALTER TABLE ALTER COLUMNcomandi?
KM.

6
@KM Un problema è se stai modificando un grande tavolo. Ogni affermazione significa una nuova scansione, ma se fosse possibile modificare più colonne, tutte le modifiche avrebbero potuto essere molto più veloci
erikkallen

@erikkallen, quindi gli strumenti SSMS di solito generano i loro script: crea una nuova tabella e replica FK e indici, ecc., elimina la tabella originale e quindi rinomina la nuova tabella,
KM.

Far cadere e ricreare le tabelle è un'operazione piuttosto intensa. Ora è disabilitato per impostazione predefinita in SSMS e probabilmente per una buona ragione.
Giovedì

"Each statement means a new scan": Non necessariamente @erikkallen. In alcuni casi la colonna ALTER è una semplice modifica dei metadati. Domani SQL Internals - Physical Table Structure under the hood, and implementation on real case scenariospuoi unirti alla mia lezione su " " per vedere tutto in pratica :-)
Ronen Ariely,

26

Non è possibile eseguire più ALTER COLUMNazioni all'interno di una singola ALTER TABLEistruzione.

Vedi la ALTER TABLEsintassi qui

Puoi fare più ADDo più DROP COLUMN, ma solo uno ALTER COLUMN.


17

Come altri hanno risposto, sono necessarie più ALTER TABLEdichiarazioni.
Prova a seguire:

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

12

La seguente soluzione non è una singola istruzione per l'alterazione di più colonne, ma sì, semplifica la vita:

  1. Genera lo CREATEscript di una tabella .

  2. Sostituisci CREATE TABLEcon ALTER TABLE [TableName] ALTER COLUMNper la prima riga

  3. Rimuovi le colonne indesiderate dall'elenco.

  4. Modifica i tipi di dati delle colonne come desideri.

  5. Eseguire un Trova e sostituisci ... come segue:

    1. Trova: NULL,
    2. Sostituirlo con: NULL; ALTER TABLE [TableName] ALTER COLUMN
    3. Premi il pulsante Sostituisci .
  6. Esegui lo script.

Spero che farà risparmiare molto tempo :))


6

Come molti altri hanno già detto, dovrai utilizzare più ALTER COLUMNistruzioni, una per ogni colonna che desideri modificare.

Se si desidera modificare tutte o più delle colonne della tabella nello stesso tipo di dati (ad esempio l'espansione di un campo VARCHAR da 50 a 100 caratteri), è possibile generare automaticamente tutte le istruzioni utilizzando la query seguente. Questa tecnica è utile anche se si desidera sostituire lo stesso carattere in più campi (come rimuovere \ t da tutte le colonne).

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'

Questo genera una ALTER TABLEdichiarazione per ogni colonna per te.


1

Se si apportano le modifiche in Management Studio e si generano script, crea una nuova tabella e inserisce i vecchi dati in quello con i tipi di dati modificati. Ecco un piccolo esempio che modifica i tipi di dati di due colonne

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

Se non vuoi scrivere tu stesso tutto e cambiare tutte le colonne nello stesso tipo di dati, questo può semplificare:

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

È possibile copiare e incollare l'output come query


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)

per gentile concessione di devio


0

Grazie all'esempio di codice di Evan, sono stato in grado di modificarlo di più e di renderlo più specifico per le tabelle che iniziano, nomi di colonne specifici E gestire anche i dettagli per i vincoli. Ho eseguito quel codice, quindi ho copiato la colonna [CODICE] e l'ho eseguito senza problemi.

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;

NON è una buona soluzione. Cursori e loop dovrebbero essere evitati a TUTTI i costi !!!
Ray K.

1
Non è vero, Ray. Cursori e loop vanno bene per alcune attività DDL e altre attività necessariamente RBR.
Jeff Moden,

-3

Possiamo modificare più colonne in una singola query in questo modo:

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

Fornisci le query come separate da virgola.


4
Penso che sia MySql? La domanda era per SQL Server e questo non funziona in SQL Server
Tjipke,

-4

Metti la ALTER COLUMNdichiarazione all'interno di una parentesi, dovrebbe funzionare.

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

-4

Se ho compreso correttamente la tua domanda, puoi aggiungere più colonne in una tabella utilizzando la query di seguito indicata.

Query:

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

4
L'OP ha chiesto informazioni sulla colonna ALTER, non su ADD.
DR
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.