Pergunta

Eu tenho um banco de dados cheio de colunas DateTime2 do que precisa ser movido para um banco de dados SQL 2005. Então, eu preciso converter todas essas colunas DATETime2 (7) em DateTime.

Como posso fazer isso?

No momento, consegui selecionar o nome da tabela e o nome da coluna para todas as colunas com o DataTyType DateTime2 como este:

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'

Eu simplesmente não sei como fazer o resto.

Foi útil?

Solução

... Então você itera seus resultados com o cursor e executa dinamicamente o DDL como:

ALTER TABLE myTable ALTER COLUMN myColumn datetime [NOT] NULL

para que você obtenha algo semelhante a isso (não testado):

Editar: Verificação adicional de capacidade de nulo também:

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;

Outras dicas

Eu sei que esse tópico é antigo, mas estou fazendo a mesma coisa hoje e só queria oferecer minha técnica. Sempre que preciso fazer muitas instruções DDL, crio um TSQL que gera o TSQL necessário e, em seguida, copie os resultados para a janela de consulta e executá -la. Você não precisa escrever todo o código do cursor, como a @van sugestão (embora isso funcione bem).

Então, para sua situação, basta executar a declaração SQL:

select 'ALTER TABLE ' + table_name + ' ALTER COLUMN ' + column_name + ' datetime [NOT] NULL' 
from INFORMATION_SCHEMA.columns 
where data_type = 'datetime2(7)'.

Em seguida, copie os resultados para uma nova janela de consulta e execute -a. Às vezes você precisa adicionar "GO" declarações em sua própria linha entre comandos. Se sim, adicione char(13) + 'GO' na sua sequência de saída.

Além disso, execute a consulta no SQL MGMT Studio com a opção "Resultados para texto", em vez da opção "resultados para grade".

Melhorou a resposta acima para atender esquemas

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;

Precisava fazer isso hoje para todas as tabelas de usuário em um esquema e não estava satisfeito com nenhuma das respostas existentes. Especialmente, algumas das minhas colunas DateTime tinham padrões, o que realmente ninguém precisava, mas impediu os comandos da tabela de alter. Então, escrevi um script que apenas solta esses padrões e depois altera as colunas. Preserva a anulação e pode lidar com nomes que contêm espaços, hífens etc. Cuidado, não recrie os padrões posteriormente.

Se você estiver na mesma situação, pode usar este script estável e testado, que também garante que não haja truncamento silencioso da variável nvarchar (max) usada para compor as instruções 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

Ele usa tabelas de sintaxe e esquema antigas, por isso está funcionando na versão 2008 do SQL Server (que foi a primeira a apoiar datetime2) até 2016.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top