Estou gerando algumas consultas de forma automática com o código que escrevi para SELECT em um banco de dados Pg remoto e inserir em um banco de dados SQL Server local. No entanto, um deles está gerando este erro:
[Microsoft] [Driver ODBC do SQL Server] [SQL Server] Dados binários ou de string seriam truncados. (SQL-22001) [o estado era 22001 agora 01000]
[Microsoft] [Driver ODBC SQL Server] [SQL Server] A instrução foi encerrada. (SQL-01000) em. \ Insert.pl linha 106.
Como faço para descobrir qual coluna está gerando esse erro e não tem o comprimento para o entrada? Existe uma maneira de fazer isso sem adivinhar a força bruta todas as varchar
?
Resposta
Não, não está registrado em lugar nenhum. Vá votar e declarar seu caso de negócios; este é um na longa lista de coisas que devem ser corrigidas no SQL Server.
Isso foi solicitado anos atrás no Connect (provavelmente primeiro no SQL Server 2000 ou 2005), depois novamente no novo sistema de feedback:
E agora ele foi entregue nas seguintes versões:
No primeiro CTP público do SQL Server 2019, ele só aparece sob o sinalizador de rastreamento 460. Isso parece meio secreto, mas foi publicado em este white paper da Microsoft . Este será o comportamento padrão (sem sinalizador de rastreamento necessário) daqui para frente, embora você possa controlar isso por meio de uma nova configuração de escopo de banco de dados VERBOSE_TRUNCATION_WARNINGS
.
Aqui é um exemplo:
USE tempdb; GO CREATE TABLE dbo.x(a char(1)); INSERT dbo.x(a) VALUES("foo"); GO
Resultado em todas as versões com suporte anteriores ao SQL Server 2019:
Msg 8152, Nível 16, Estado 30, Linha 5
String ou dados binários seriam truncados.
A instrução foi encerrada.
Agora, no SQL Server 2019 CTPs, com o sinalizador de rastreamento habilitado:
DBCC TRACEON(460); GO INSERT dbo.x(a) VALUES("foo"); GO DROP TABLE dbo.x; DBCC TRACEOFF(460);
O resultado mostra a tabela, a coluna e o ( truncado , não full ) valor:
Msg 2628, Nível 16, Estado 1, Linha 11
Dados de string ou binários seriam truncados na tabela “tempdb.dbo.x”, coluna “a”. Valor truncado: “f”.
A instrução foi encerrada.
Até que você possa mover para uma versão / CU com suporte ou mover para o Banco de Dados SQL do Azure, você pode alterar seu código “automagic” para puxar o max_length de sys.columns
, junto com o nome que você deve obter lá de qualquer maneira, e então aplicar LEFT(column, max_length)
ou o que quer que seja o equivalente de PG. Ou, uma vez que isso significa apenas que você perderá dados silenciosamente, descubra quais colunas são incompatíveis e corrija as colunas de destino para que se ajustem a todos os dados da fonte. Dado o acesso de metadados a ambos os sistemas, e o fato de que você já está escrevendo uma consulta que deve corresponder automagicamente às colunas fonte -> destino (caso contrário, este erro dificilmente seria seu maior problema), você não deveria ter que fazer força bruta adivinhando.
Resposta
Se você tiver acesso para executar o SQL Server Import and Export Wizard no SQL Server Management Studio (clique com o botão direito do mouse em banco de dados> Tarefas> Importar dados …), crie uma tarefa que importe do SQL Client usando sua consulta como fonte de dados para a tabela de destino.
Antes de executar a importação, você pode revisar o mapeamento de dados e ele informará quais colunas têm tipos de campo inconsistentes. E se você executar a tarefa de importação, ela informará quais colunas falharam ao importar.
Exemplo de aviso de validação:
Aviso 0x802092a7: Tarefa 1 de fluxo de dados: pode ocorrer truncamento devido à inserção de dados da coluna de fluxo de dados “NARRATIVA” com um comprimento de 316 para a coluna de banco de dados “NARRATIVA” com um comprimento de 60. (Assistente de importação e exportação do SQL Server)
Resposta
Finalmente Microsoft decidiu fornecer informações significativas para String or binary would be truncated
a partir do SQL Server 2016 SP2 CU, SQL Server 2017 CU12 e no SQL Server 2019.
As informações agora inclui a coluna da tabela ofensiva (nome totalmente qualificado) e o valor ofensivo (truncado em 120 caracteres):
Msg 2628, Nível 16, Estado 1, Linha x String ou dados binários seriam truncados na tabela “TheDb.TheSchema.TheTable “, coluna” TheColumn “. Valor truncado:” … “. A declaração foi encerrada.
Resposta
Em última análise, não consegui encontrar uma maneira de obter as informações da coluna sem escrevê-las sozinho.
Esta mensagem de erro foi gerada por DBD::ODBC
, você também pode usar sys.columns (max_length)
(não sei como).
Usei um código como este em minha lista de colunas para obter uma lista de matrizes com dois elementos, COLUMN_NAME
e MAX_LENGTH
(documentado em DBI column_info()
).
my @max_lengths = map [ @{$_->fetchall_arrayref->[0]}[3,6] ] , map $dbh_mssql->column_info("database", "dbo", $dest_table, $_) , @col_mssql ;
Então eu peguei as exceções em INSERT
e imprimi algo útil. Neste exemplo, @$row
são os dados enviados para sth->execute()
if ($@) { warn "$@\n"; for ( my $idx=0; $idx <= $#{ $row }; $idx++ ) { Dumper { maxlength => $max_lengths[$idx]->[1] , name => $max_lengths[$idx]->[0] , length => length( $row->[$idx] ) , content => $row->[$idx] }; } die; }
Além disso, vote e vote positivamente a outra resposta
sys.columns
porque não tinha absolutamente nenhuma ideia de qual código você está usando atualmente para ” automagicamente ” gere suas consultas. Realmente não há ‘ muito mais complexo que eu poderia imaginar sobre como incorporar em seu código do queSELECT name, object_id, max_length FROM sys.columns;
. Como você já tem um código de automagic que deve estar fazendo isso – ou algo muito parecido – eu não ‘ achei que um exemplo fosse necessário.sys.columns
funciona com duas colunas que têm o mesmoname
. Além disso, fiz a coisa funcionar usando a biblioteca em vez desys
, por que eu faria essa como a resposta escolhida?Microsoft SQL doesn't have x, do y instead
é uma contribuição válida, mas se seuy
for inferior ao meuy
, eu ‘ vou fazer algo diferente e marcá-lo como escolhido.