Jag genererar några frågor automatiskt med kod jag skrev till SELECT från en fjärr Pg-databas och sätter in i en lokal SQL Server-databas. Men en av dem genererar det här felet:
[Microsoft] [ODBC SQL Server Driver] [SQL Server] Sträng- eller binärdata skulle trunkeras. (SQL-22001) [tillståndet var 22001 nu 01000]
[Microsoft] [ODBC SQL Server Driver] [SQL Server] Uttalandet har avslutats. (SQL-01000) på. \ Insert.pl rad 106.
Hur får jag reda på vilken kolumn som genererar det felet och saknar längden för inmatning? Finns det ett sätt att göra detta utan att gissa allt varchar
?
Svar
Nej, den loggas inte någonstans. Gå att rösta och ange ditt affärsfall; detta är en på den långa listan över saker som ska fixas i SQL Server.
Detta begärdes för flera år sedan på Connect (troligen först i SQL Server 2000 eller 2005), sedan igen på det nya återkopplingssystemet:
Och nu har den levererats i följande versioner:
I den allra första offentliga CTP i SQL Server 2019, dyker den bara upp under spårflagga 460. Det låter typ av hemlighet, men det publicerades i detta Microsoft whitepaper . Detta kommer att vara standardbeteendet (ingen spårningsflagga krävs) framöver, men du kommer att kunna kontrollera detta via en ny konfiguration för databasomfattning VERBOSE_TRUNCATION_WARNINGS
.
Här är ett exempel:
USE tempdb; GO CREATE TABLE dbo.x(a char(1)); INSERT dbo.x(a) VALUES("foo"); GO
Resultat i alla versioner som stöds före SQL Server 2019:
Msg 8152, nivå 16, tillstånd 30, rad 5
Sträng eller binär data skulle trunkeras.
Uttalandet har avslutats.
Nu, på SQL Server 2019 CTP: er, med spårningsflaggan aktiverad:
DBCC TRACEON(460); GO INSERT dbo.x(a) VALUES("foo"); GO DROP TABLE dbo.x; DBCC TRACEOFF(460);
Resultatet visar tabellen, kolumnen och ( trunkerad , inte fullt ) värde:
Msg 2628, nivå 16, tillstånd 1, rad 11
Sträng- eller binära data trunkeras i tabellen ”tempdb.dbo.x”, kolumn ”a”. Trunkerat värde: ”f”.
Uttalandet har avslutats.
Tills du kan flytta till en version / CU som stöds eller flytta till Azure SQL Database kan du ändra din ”automagisk” kod för att faktiskt dra max_längden från sys.columns
, tillsammans med namnet som du måste komma dit ändå, och sedan använda LEFT(column, max_length)
eller vad som helst som motsvarar PG. Eller eftersom det bara betyder att du tyst tappar data, ta reda på vilka kolumner som inte stämmer överens och fixa målkolumnerna så att de passar alla data från källan. Med tanke på metadataåtkomst till båda systemen och det faktum att du redan skriver en fråga som automatiskt måste matcha källan -> målkolumner (annars skulle detta fel knappast vara ditt största problem), skulle du inte behöva göra någon brute-force gissning alls.
Svar
Om du har tillgång till att köra SQL Server Import och Export Wizard från SQL Server Management Studio (högerklicka på databasen> Uppgifter> Importera data …), skapa en uppgift som importeras från SQL Client med din fråga som datakälla till måltabellen.
Innan du kör importen kan du granska datakartläggningen och den kommer att berätta vilka kolumner som har inkonsekventa fälttyper. Och om du kör importuppgiften kommer den att berätta vilka kolumner som inte kunde importeras.
Exempelvalideringsvarning:
Varning 0x802092a7: Dataflödesuppgift 1: Trunkering kan inträffa på grund av infogning av data från dataflödeskolumnen ”NARRATIVE” med längden 316 i databaskolumnen ”NARRATIVE” med en längd på 60. (SQL Server Import och Export-guiden)
Svar
Slutligen Microsoft har beslutat att ge meningsfull information för String or binary would be truncated
med start från SQL Server 2016 SP2 CU, SQL Server 2017 CU12 och i SQL Server 2019.
Informationen innehåller nu både kränkande tabellkolumn (fullständigt kvalificerat namn) och det kränkande värdet (trunkerat med 120 tecken):
Msg 2628, nivå 16, tillstånd 1, Linje x Sträng eller binära data trunkeras i tabellen ”TheDb.TheSchema.TheTable ”, kolumn” TheColumn ”. Trunkerat värde:” … ”. Uttalandet har avslutats.
Svar
I slutändan kunde jag inte hitta ett sätt att få kolumninformationen utan att skriva den själv.
Detta felmeddelande genererades av DBD::ODBC
, men du kan också använda sys.columns (max_length)
(jag vet bara inte hur).
Jag använde kod så här över min kolumnlista för att få en lista med matriser med två element, COLUMN_NAME
och MAX_LENGTH
(dokumenterad i DBI column_info()
).
my @max_lengths = map [ @{$_->fetchall_arrayref->[0]}[3,6] ] , map $dbh_mssql->column_info("database", "dbo", $dest_table, $_) , @col_mssql ;
Sedan fångade jag undantagen på INSERT
och skrev ut något användbart. I detta exempel är @$row
data som skickas till 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; }
Vänligen rösta och rösta det andra svaret
sys.columns
för jag hade absolut ingen aning om vilken kod du för närvarande använder för att ” automatiskt ” generera dina frågor. Det finns verkligen inte ’ t för mycket mer komplicerat jag kan gissa om att införliva i din kod änSELECT name, object_id, max_length FROM sys.columns;
. Eftersom du redan har en automagisk kod som måste göra detta – eller något som mycket liknar det – tyckte jag inte ’ att ett exempel var nödvändigt.sys.columns
fungerar med två kolumner som har sammaname
. Dessutom fick jag jobbet med biblioteket istället försys
, varför skulle jag göra det som det valda svaret?Microsoft SQL doesn't have x, do y instead
är ett giltigt bidrag, men om diny
är sämre än miny
, ’ ska göra något annorlunda och markera det som valt.