T-SQL: Convertir datatime2 en datetime pour toutes les colonnes de type datetime2
Question
J'ai une base de données remplie de colonnes datetime2 qu'il est nécessaire de déplacer vers une base de données SQL 2005. J'ai donc besoin de convertir toutes ces colonnes datetime2 (7) en datetime.
Comment puis-je m'y prendre?
À l'heure actuelle, j'ai réussi à sélectionner le nom de la table et le nom de la colonne pour toutes les colonnes avec le type de données datetime2 comme ceci:
SELECT t.name, c.name, i.DATA_TYPE
FROM sys.tables AS t
JOIN sys.columns c ON t.object_id = c.object_id
JOIN information_schema.columns i ON i.TABLE_NAME = t.name AND i.COLUMN_NAME = c.name
WHERE i.data_type = 'datetime2'
Je ne sais tout simplement pas comment faire le reste.
La solution
... alors vous parcourez vos résultats avec le CURSEUR et exécutez dynamiquement le DDL comme:
ALTER TABLE myTable ALTER COLUMN myColumn datetime [NOT] NULL
afin que vous obteniez quelque chose de similaire à ceci (non testé):
Modifier: ajout d'une vérification de la nullité:
DECLARE @SQL AS NVARCHAR(1024)
DECLARE @TBL AS NVARCHAR(255)
DECLARE @COL AS NVARCHAR(255)
DECLARE @NUL AS BIT
DECLARE CUR CURSOR FAST_FORWARD FOR
SELECT t.name, c.name, c.is_nullable
FROM sys.tables AS t
JOIN sys.columns c ON t.object_id = c.object_id
JOIN information_schema.columns i ON i.TABLE_NAME = t.name AND i.COLUMN_NAME = c.name
WHERE i.data_type = 'datetime2'
ORDER BY t.name, c.name
OPEN CUR
FETCH NEXT FROM CUR INTO @TBL, @COL, @NUL
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @SQL = 'ALTER TABLE ' + @TBL + ' ALTER COLUMN ' + @COL + ' datetime' + (CASE WHEN @NUL=1 THEN '' ELSE ' NOT' END) + ' NULL;'
EXEC sp_executesql @SQL
FETCH NEXT FROM CUR INTO @TBL, @COL, @NUL
END
CLOSE CUR;
DEALLOCATE CUR;
Autres conseils
Je sais que ce fil est vieux, mais je fais la même chose aujourd'hui et je voulais juste offrir ma technique. Chaque fois que j'ai besoin de faire beaucoup d'instructions DDL, je crée un TSQL qui génère le TSQL requis, puis copiez simplement les résultats dans la fenêtre de requête et exécutez-le. Vous n'avez pas besoin d'écrire tout le code du curseur comme @van suggestion (bien que cela fonctionne très bien).
Dans votre cas, exécutez simplement l'instruction SQL:
select 'ALTER TABLE ' + table_name + ' ALTER COLUMN ' + column_name + ' datetime [NOT] NULL'
from INFORMATION_SCHEMA.columns
where data_type = 'datetime2(7)'.
Ensuite, copiez les résultats dans une nouvelle fenêtre de requête et exécutez-les. Parfois, vous devez ajouter des instructions & GO; "
sur leur propre ligne entre les commandes. Si tel est le cas, ajoutez char (13) + 'GO'
dans votre chaîne de sortie.
Assurez-vous également que la requête est exécutée dans SQL Mgmt Studio avec l'option "Résultats en texte". option à la place de l'option "Résultats de la grille" option.
Amélioration de la réponse ci-dessus pour prendre en charge les schémas
DECLARE @SQL AS NVARCHAR(1024)
DECLARE @TBL AS NVARCHAR(255)
DECLARE @COL AS NVARCHAR(255)
DECLARE @SCH AS NVARCHAR(255)
DECLARE @NUL AS BIT
DECLARE CUR CURSOR FAST_FORWARD FOR
SELECT t.name AS TableName, c.name ColumnName, s.name AS SchemaName, c.is_nullable
FROM sys.tables AS t
JOIN sys.columns c ON t.object_id = c.object_id
JOIN information_schema.columns AS i ON i.TABLE_NAME = t.name AND i.COLUMN_NAME = c.name
JOIN sys.schemas AS s on t.schema_id = s.schema_id
WHERE i.data_type = 'datetime2'
ORDER BY t.name, c.name
OPEN CUR
FETCH NEXT FROM CUR INTO @TBL, @COL, @SCH, @NUL
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @SQL = 'ALTER TABLE ['+@SCH+'].[' + @TBL + '] ALTER COLUMN [' + @COL + '] datetime' + (CASE WHEN @NUL=1 THEN '' ELSE ' NOT' END) + ' NULL;'
EXEC sp_executesql @SQL
FETCH NEXT FROM CUR INTO @TBL, @COL,@SCH, @NUL
END
CLOSE CUR;
DEALLOCATE CUR;
Nécessaire de le faire aujourd'hui pour toutes les tables utilisateur d'un schéma et n'était satisfait d'aucune des réponses existantes. Surtout, certaines de mes colonnes datetime avaient des valeurs par défaut, dont personne n’avait besoin, mais gênaient les commandes ALTER TABLE. J'ai donc écrit un script qui supprime simplement ces valeurs par défaut, puis modifie les colonnes. Il préserve la nullité et peut gérer les noms contenant des espaces, des tirets, etc. Attention, il ne recrée pas les valeurs par défaut par la suite.
Si vous êtes dans la même situation, vous pouvez utiliser ce script stable et testé, qui garantit également l'absence de troncature silencieuse de la variable nvarchar (max) utilisée pour composer les instructions DDL:
DECLARE @sql AS nvarchar(max)=N''
--1. "ALTER TABLE [Tablename] DROP CONSTRAINT [DF__Tablename__Colname__Obfuscation]"
SELECT @sql=CAST('' AS nvarchar(MAX))+@sql
+N'ALTER TABLE ['+o.[name]+N'] DROP CONSTRAINT ['+co.[name]+']'
FROM sysconstraints c
INNER JOIN sysobjects o ON o.[id]=c.[id]
INNER JOIN syscolumns col ON col.[id]=o.[id] AND col.colid=c.colid
INNER JOIN sysobjects co ON co.[id]=c.constid
WHERE col.xtype=61 --datetime
EXEC sp_executesql @sql
--2. change type of all datetime columns
SELECT @sql=N''
SELECT @sql=CAST('' AS nvarchar(MAX))+@sql
+N'ALTER TABLE ['
+convert(nvarchar(max),t.name)
+N'] ALTER COLUMN ['
+convert(nvarchar(max),c.name)
+N'] datetime2 '
+CASE WHEN c.is_nullable = 1 THEN N'' ELSE N'NOT' END
+N' NULL;'+convert(nvarchar(max),char(13)+char(10))
FROM sys.tables t
INNER JOIN sys.columns c ON t.object_id = c.object_id
INNER JOIN sys.types st ON st.system_type_id = c.system_type_id
WHERE st.name=N'datetime'
AND t.xtype=N'U' --user tables only
ORDER BY t.[name]
EXEC sp_executesql @sql
Il utilise une syntaxe et des tables de schéma anciennes. Il fonctionne donc à partir de SQL Server version 2008 (qui a été le premier à prendre en charge datetime2
) à 2016.