T-SQL: преобразование datatime2 в datetime для всех столбцов типа datetime2

У меня есть база данных, полная столбцов 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'

Я просто не знаю, как сделать все остальное.


person David Murdoch    schedule 18.09.2009    source источник
comment
Почему вы объединяете три таблицы, когда всю эту информацию можно получить из information_schema.columns?   -  person Kibbee    schedule 19.09.2009
comment
@ван, @Дэвид. Вы можете проверить столбец is_nullable в sys.columns, чтобы убедиться, что NOT NULL необходим в ALTER COLUMN.   -  person Lukasz Lysik    schedule 19.09.2009


Ответы (4)


... затем вы перебираете свои результаты с помощью 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;
person van    schedule 18.09.2009
comment
Извините, я действительно плохо знаю SQL. Можно поподробнее? - person David Murdoch; 19.09.2009
comment
добавил код в ответ. в основном вам нужно изменить тип столбца, верно? вы можете сделать это, используя синтаксис ALTER TABLE... ALTER COLUMN.... С помощью курсора вы можете просто выполнить для всех найденных вами столбцов в своего рода цикле. Вы можете добавить проверку допустимости значений столбца NULL, как отметил Лукаш, и добавить NOT NULL в инструкцию. - person van; 19.09.2009
comment
Спасибо за вашу помощь! Я думаю, это может сработать. Но у меня также есть другая проблема, потому что многие из этих столбцов имеют ограничения/триггеры. Я получаю сообщение об ошибке о том, что объект «DF_CreatedDate» зависит от столбца «CreatedDate». - person David Murdoch; 19.09.2009
comment
в этом случае вы можете сгенерировать другой динамический SQL и выполнить его непосредственно перед ALTER COLUMN... : ALTER TABLE xxx NOCHECK CONSTRAINT DR_CreatedDate... или что-то подобное. но в таких случаях вы можете захотеть посмотреть, что такое код для этого ограничения, и если это что-то вроде DEFAULT (GETDATE()), то вы можете сначала удалить его, затем изменить тип данных, а затем добавить его обратно. - person van; 19.09.2009

Я знаю, что эта тема устарела, но сегодня я делаю то же самое и просто хочу предложить свою технику. Всякий раз, когда мне нужно выполнить множество операторов DDL, я создаю один TSQL, который генерирует необходимый TSQL, а затем просто копирует результаты в окно запроса и запускает его. Вам не нужно писать весь код курсора, как предложение @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 с параметром «Результаты в текст» вместо параметра «Результаты в сетку».

person sisdog    schedule 31.03.2011
comment
В заключение, я конвертирую все свои столбцы datetime в datetime2(7), так что вот SQL, который я использовал: select 'ALTER TABLE [' + t.table_name + '] ALTER COLUMN [' + column_name + '] datetime2(7) ' + (case when is_nullable = 'NO' then 'NOT' else '' end) + ' NULL' from INFORMATION_SCHEMA.columns c inner join information_schema.TABLES t on c.TABLE_NAME = t.table_name where data_type = 'datetime' and t.TABLE_TYPE = 'base table' order by t.table_name - person sisdog; 31.03.2011

Улучшен приведенный выше ответ для удовлетворения схем

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;
person Lord Darth Vader    schedule 14.11.2017
comment
Жаль, что я не увидел этот ответ раньше, буквально только что написал точно такой же SQL (за исключением того, что я использовал локальный курсор). Примечательно, что в этом ответе также учитываются имена таблиц и столбцов с пробелами/специальными символами, в то время как в принятом ответе нет - person Erik A; 02.01.2018

Необходимо было сделать это сегодня для всех пользовательских таблиц в схеме, и ни один из существующих ответов не удовлетворил. В частности, некоторые из моих столбцов даты и времени имели значения по умолчанию, которые на самом деле никому не были нужны, но мешали командам ALTER TABLE. Поэтому я написал скрипт, который просто отбрасывает эти значения по умолчанию, а затем меняет столбцы. Он сохраняет обнуляемость и может обрабатывать имена, содержащие пробелы, дефисы и т. д. Внимание, впоследствии он не воссоздает значения по умолчанию.

Если вы находитесь в такой же ситуации, вы можете использовать этот стабильный и проверенный скрипт, который также гарантирует отсутствие усечения переменной nvarchar(max), используемой для составления операторов 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

Он использует древний синтаксис и таблицы схемы, поэтому он работает с версии SQL Server 2008 (которая первой поддерживала datetime2) до 2016 года.

person Cee McSharpface    schedule 27.01.2018