2009-09-18 10 views
3

J'ai une base de données remplie de colonnes datetime2 qui doit être déplacée vers une base de données SQL 2005. Donc, j'ai besoin de convertir toutes ces colonnes datetime2 (7) en datetime.T-SQL: Convertir datatime2 en datetime pour toutes les colonnes de type datetime2

Comment puis-je faire cela?

En ce moment je suis parvenu à 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 pas comment faire le reste.

+0

Pourquoi vous rejoignons trois tables lorsque toutes ces informations peuvent être obtenues auprès information_schema .columns? – Kibbee

+2

@van, @David. Vous pouvez vérifier la colonne is_nullable dans sys.Colonnes à vérifier si NOT NULL est nécessaire dans ALTER COLUMN –

Répondre

5

... vous itérer sur vos résultats avec le curseur dynamique et d'exécuter le DDL comme:

ALTER TABLE myTable ALTER COLUMN myColumn datetime [NOT] NULL 

afin que vous obtenez quelque chose de semblable à ce (non testé):

Edit: Ajout d'une vérification nul capacité ainsi:

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; 
+0

Désolé, je ne connais pas vraiment le SQL. Peut-on développer ça? –

+0

a ajouté le code à la réponse. fondamentalement, vous devez changer le type de la colonne, non? vous pouvez le faire en utilisant la syntaxe ALTER TABLE ... ALTER COLUMN ... Avec l'aide du curseur, vous pouvez simplement exécuter pour toutes les colonnes que vous avez trouvées dans une sorte de boucle. Vous pouvez ajouter la vérification de la nullabilité de la colonne comme indiqué par Lucasz et ajouter NOT NULL à l'instruction. – van

+0

modifié: vérification supplémentaire de la nullabilité (non testée). Bravo – van

2

Je sais que ce fil est vieux, mais je fais la même chose aujourd'hui et je voulais juste offe r 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 nécessaire, 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 suggestion @van (bien que cela fonctionne bien).

Alors, pour votre situation, il suffit d'exécuter 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 l'exécuter. Parfois, vous devez ajouter des instructions "GO" sur leur propre ligne entre les commandes. Si c'est le cas, ajoutez char(13) + 'GO' dans votre chaîne de sortie. De plus, assurez-vous d'exécuter la requête dans SQL Mgmt Studio avec l'option "Results to Text" au lieu de l'option "Results to Grid".

+1

Juste un dernier suivi, je convertis toutes mes colonnes datetime en datetime2 (7) alors voici le SQL que j'ai utilisé: 'select 'ALTER TABLE [' + t.nom_table + '] ALTER COLUMN [' + column_name + '] datetime2 (7)' \t + (cas où is_nullable = 'NO' puis 'NOT' else '' end) + 'NULL' from INFORMATION_SCHEMA.colonnes c jointure interne \t information_schema.TABLES t sur c.TABLE_NAME = t.table_name où data_type = 'datetime' et t.TABLE_TYPE = 'table de base' order par t.table_name' – sisdog

1

amélioré la réponse ci-dessus pour répondre aux 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 ['[email protected]+'].[' + @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; 
+0

J'aimerais avoir vu cette réponse plus tôt, littéralement je viens d'écrire exactement le même SQL (sauf que j'ai utilisé un curseur local). Il est à noter que cette réponse prend également en compte les noms de table et de colonne avec des espaces/caractères spéciaux, alors que celui accepté ne le fait pas –

0

nécessaire de le faire aujourd'hui pour toutes les tables utilisateur dans un schéma, et n'a pas été satisfait de l'une des réponses existantes. En particulier, 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 traits d'union, etc. Attention, il ne recréera 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é, ce qui rend également sûr qu'il n'y a pas troncature silencieuse de la variable nvarchar (max) utilisé 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))[email protected] 
    +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))[email protected] 
    +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 la syntaxe anciens et tables schéma, il travaille à partir de la version SQL Server 2008 (qui a été le premier à soutenir datetime2) à travers 2016.

Questions connexes