我有一个充满datetime2列的数据库,而不是需要移动到SQL 2005数据库的数据库。所以,我需要将所有这些datetime2(7)列转换为datetime。
我该怎么做呢?
现在我已经设法为datetime2数据类型的所有列选择表名和列名,如下所示:
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'
我只是不知道该怎么做。
答案 0 :(得分:5)
...然后用CURSOR迭代你的结果并动态运行DDL,如:
ALTER TABLE myTable ALTER COLUMN myColumn datetime [NOT] NULL
这样你就可以获得类似的东西(未经测试):
编辑:添加了无效能力检查:
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;
答案 1 :(得分:3)
我知道这个帖子已经老了,但我今天也在做同样的事情,只是想提供我的技术。每当我需要执行大量DDL语句时,我创建一个TSQL来生成所需的TSQL,然后将结果复制到Query窗口并运行它。您不需要像@van建议那样编写所有光标代码(虽然这样可以正常工作)。
因此,根据您的情况,只需运行sql语句:
select 'ALTER TABLE ' + table_name + ' ALTER COLUMN ' + column_name + ' datetime [NOT] NULL'
from INFORMATION_SCHEMA.columns
where data_type = 'datetime2(7)'.
然后,将结果复制到新的查询窗口并运行它。有时您需要在命令之间添加"GO"
语句。如果是这样,请将char(13) + 'GO'
添加到输出字符串中。
此外,请确保在SQL Mgmt Studio中使用"结果到文本"运行查询。选项而不是"结果到网格"选项。
答案 2 :(得分:1)
改进上述答案以迎合架构
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;
答案 3 :(得分:0)
今天需要为架构中的所有用户表执行此操作,并且对任何现有答案都不满意。特别是,我的一些日期时间列具有默认值,实际上没有人需要,但阻碍了ALTER TABLE命令。所以我写了一个脚本,只删除那些默认值,然后更改列。它保留了可空性,并且可以处理包含空格,连字符等的名称。注意,它之后不会重新创建默认值。
如果你处于相同的情况,你可以使用这个稳定且经过测试的脚本,这也确保没有用于组成DDL语句的nvarchar(max)变量的静默截断:
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
它使用古老的语法和架构表,所以它从2016年的SQL Server版本(这是第一个支持datetime2
)到2016年。