Comment modifier plusieurs colonnes à la fois dans SQL Server


143

J'ai besoin ALTERdes types de données de plusieurs colonnes dans une table.

Pour une seule colonne, ce qui suit fonctionne correctement:

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

Mais comment modifier plusieurs colonnes dans une seule instruction? Ce qui suit ne fonctionne pas:

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

1
Quel est l'avantage perçu de le faire en une seule fois?
jour du

5
@onedaywhen - Pour que SQL Server ne fasse qu'un seul passage dans la table pour effectuer toute validation nécessaire par rapport au nouveau type de données et / ou écrire les colonnes modifiées dans le nouveau format.
Martin Smith

1
Pas de grand avantage alors!
jour du

4
Contraire. Ce serait un grand avantage d'avoir un alter exécuté en 2 heures au lieu de 24 pour plusieurs colonnes sur de grandes tables.
Norbert Kardos

Réponses:


135

Ce n'est pas possible. Vous devrez le faire un par un.

Vous pouvez créer une table temporaire avec vos colonnes modifiées, copier les données, supprimer votre table d'origine et renommer votre table temporaire à votre nom d'origine.


5
+1, You will need to do this one by one.alors quel est le problème, utilisez simplement plusieurs ALTER TABLE ALTER COLUMNcommandes?
KM.

6
@KM Un problème est si vous modifiez une grande table. Chaque instruction signifie une nouvelle analyse, mais si vous pouviez modifier plusieurs colonnes, toutes les modifications auraient pu être beaucoup plus rapides
erikkallen

@erikkallen, alors faites comme les outils SSMS génèrent généralement leurs scripts: créez une nouvelle table et répliquez les FK et les index, etc., supprimez la table d'origine, puis renommez la nouvelle table,
KM.

Supprimer et recréer des tables est une opération assez intensive. Il est désactivé par défaut dans SSMS maintenant, et probablement pour une bonne raison.
jocull du

"Each statement means a new scan": Pas nécessairement @erikkallen. Dans certains cas, la colonne ALTER est un simple changement de métadonnées. Vous êtes invités à vous joindre à ma conférence demain sur " SQL Internals - Physical Table Structure under the hood, and implementation on real case scenarios" pour tout voir en pratique :-)
Ronen Ariely

26

Il n'est pas possible d'effectuer plusieurs ALTER COLUMNactions dans une seule ALTER TABLEinstruction.

Voir la ALTER TABLEsyntaxe ici

Vous pouvez en faire plusieurs ADDou plusieurs DROP COLUMN, mais un seul ALTER COLUMN.


17

Comme d'autres l'ont répondu, vous avez besoin de plusieurs ALTER TABLEdéclarations.
Essayez de suivre:

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

12

La solution suivante n'est pas une seule instruction pour modifier plusieurs colonnes, mais oui, elle simplifie la vie:

  1. Générez le CREATEscript d' une table .

  2. Remplacer CREATE TABLEpar ALTER TABLE [TableName] ALTER COLUMNpour la première ligne

  3. Supprimez les colonnes indésirables de la liste.

  4. Modifiez les types de données des colonnes comme vous le souhaitez.

  5. Effectuez une recherche et un remplacement… comme suit:

    1. Trouvez: NULL,
    2. Remplacer par: NULL; ALTER TABLE [TableName] ALTER COLUMN
    3. Appuyez sur le bouton Remplacer .
  6. Exécutez le script.

J'espère que cela vous fera gagner beaucoup de temps :))


6

Comme beaucoup d'autres l'ont dit, vous devrez utiliser plusieurs ALTER COLUMNinstructions, une pour chaque colonne que vous souhaitez modifier.

Si vous souhaitez modifier tout ou plusieurs des colonnes de votre table avec le même type de données (par exemple, étendre un champ VARCHAR de 50 à 100 caractères), vous pouvez générer automatiquement toutes les instructions à l'aide de la requête ci-dessous. Cette technique est également utile si vous souhaitez remplacer le même caractère dans plusieurs champs (par exemple en supprimant \ t de toutes les colonnes).

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'

Cela génère une ALTER TABLEdéclaration pour chaque colonne pour vous.


1

Si vous effectuez les modifications dans le studio de gestion et générez des scripts, il crée une nouvelle table et insère les anciennes données dans celle-ci avec les types de données modifiés. Voici un petit exemple de modification des types de données de deux colonnes

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

Si vous ne voulez pas tout écrire vous-même et changer toutes les colonnes avec le même type de données, cela peut vous faciliter la tâche:

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

Vous pouvez copier et coller la sortie en tant que votre requête


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)

gracieuseté de devio


0

Grâce à l'exemple de code d'Evan, j'ai pu le modifier davantage et le rendre plus spécifique aux tables commençant par des noms de colonnes spécifiques ET gérer également les spécificités des contraintes. J'ai exécuté ce code, puis j'ai copié la colonne [CODE] et l'ai exécutée sans problème.

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;

PAS une bonne solution. Les curseurs et les boucles doivent être évités à TOUT prix !!!
Ray K.

1
Pas vrai, Ray. Les curseurs et les boucles conviennent à certaines tâches DDL et à d'autres tâches nécessairement RBR.
Jeff Moden

-3

Nous pouvons modifier plusieurs colonnes dans une seule requête comme ceci:

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

Donnez simplement les requêtes séparées par des virgules.


4
Je pense que c'est MySql? La question était pour SQL Server, et cela ne fonctionne pas dans le serveur SQL
Tjipke

-4

Mettez l' ALTER COLUMNinstruction dans un crochet, cela devrait fonctionner.

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

-4

Si j'ai bien compris votre question, vous pouvez ajouter plusieurs colonnes dans un tableau en utilisant la requête mentionnée ci-dessous.

Requete:

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

4
L'OP a posé des questions sur la colonne ALTER, pas sur ADD.
DR
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.