Jak zidentyfikować kolumny odpowiedzialne za “ ciąg lub dane binarne zostaną obcięte. ”

Niektóre zapytania generuję automagicznie za pomocą kodu, który napisałem do SELECT ze zdalnej bazy danych Pg i wstawiam je do lokalnej bazy danych SQL Server. Jednak jeden z nich generuje ten błąd:

[Microsoft] [ODBC SQL Server Driver] [SQL Server] Ciąg lub dane binarne zostałyby obcięte. (SQL-22001) [stan to 22001, teraz 01000]

[Microsoft] [Sterownik ODBC SQL Server] [SQL Server] Instrukcja została zakończona. (SQL-01000) pod adresem. \ Insert.pl line 106.

Jak sprawdzić, która kolumna generuje ten błąd i nie zawiera długości Wejście? Czy można to zrobić bez brutalnego zgadywania wszystkich varchar?

Odpowiedź

Nie, nie jest nigdzie rejestrowany. Idź głosować i przedstaw swoje uzasadnienie biznesowe; jest to jedna z długiej listy rzeczy, które powinny zostać naprawione w SQL Server.

Poproszono o to lata temu w Connect (prawdopodobnie najpierw w ramach czasowych SQL Server 2000 lub 2005), a potem znowu w nowym systemie opinii:

A teraz został dostarczony w następujących wersjach:

W pierwszym publicznym CTP SQL Server 2019 pojawia się tylko pod flagą śledzenia 460. Brzmi to trochę tajemniczo, ale zostało opublikowane w ten oficjalny dokument firmy Microsoft . Będzie to domyślne zachowanie (nie jest wymagana flaga śledzenia) w przyszłości, chociaż będzie można to kontrolować za pomocą nowej konfiguracji zakresu bazy danych VERBOSE_TRUNCATION_WARNINGS.

Tutaj to przykład:

USE tempdb; GO CREATE TABLE dbo.x(a char(1)); INSERT dbo.x(a) VALUES("foo"); GO 

Wynik we wszystkich obsługiwanych wersjach starszych niż SQL Server 2019:

Msg 8152, poziom 16, stan 30, wiersz 5
Dane ciągowe lub binarne zostałyby obcięte.
Instrukcja została zakończona.

Teraz na serwerach CTP programu SQL Server 2019, z włączoną flagą śledzenia:

DBCC TRACEON(460); GO INSERT dbo.x(a) VALUES("foo"); GO DROP TABLE dbo.x; DBCC TRACEOFF(460); 

Wynik pokazuje tabelę, kolumnę i ( obcięte , a nie pełna ) wartość:

Msg 2628, poziom 16, Stan 1, Wiersz 11
Ciąg lub dane binarne zostałyby obcięte w tabeli „tempdb.dbo.x”, w kolumnie „a”. Obcięta wartość: „f”.
Instrukcja została zakończona.

Dopóki nie będzie można przejść do obsługiwanej wersji / CU lub do Azure SQL Database, można zmienić Kod „automagic”, aby faktycznie pobrać max_length z sys.columns, wraz z nazwą, którą i tak musisz tam dostać, a następnie zastosować LEFT(column, max_length) lub jakikolwiek odpowiednik PG jest. Lub, ponieważ oznacza to po prostu, że po cichu stracisz dane, dowiedz się, które kolumny są niedopasowane i napraw kolumny docelowe, aby pasowały do wszystkich danych ze źródła. Biorąc pod uwagę dostęp metadanych do obu systemów i fakt, że już piszesz zapytanie, które musi automagicznie pasować do kolumn źródłowych -> docelowych (w przeciwnym razie ten błąd nie byłby największym problemem), nie powinieneś wykonywać żadnej brutalnej siły zgadywanie w ogóle.

Odpowiedź

Jeśli masz dostęp do uruchomienia Kreatora importu i eksportu SQL Server z SQL Server Management Studio (baza danych kliknij prawym przyciskiem myszy> Zadania> Importuj dane …), utwórz zadanie, które importuje dane z klienta SQL, używając zapytania jako źródła danych do tabeli docelowej.

Przed rozpoczęciem importu możesz przejrzeć mapowanie danych i powie Ci, które kolumny mają niespójne typy pól. A jeśli uruchomisz zadanie importu, powie Ci, których kolumn nie udało się zaimportować.

Przykładowe ostrzeżenie o walidacji:

Ostrzeżenie 0x802092a7: Zadanie przepływu danych 1: Może wystąpić obcięcie z powodu wstawienia danych z kolumny przepływu danych „NARRATIVE” o długości 316 do kolumny bazy danych „NARRATIVE” o długości 60. (Kreator importu i eksportu SQL Server)

Odpowiedź

Wreszcie Microsoft postanowił dostarczyć znaczące informacje dla String or binary would be truncated, począwszy od SQL Server 2016 SP2 CU, SQL Server 2017 CU12 i SQL Server 2019.

Informacje zawiera teraz zarówno kolumnę tabeli naruszającej zasady (w pełni kwalifikowana nazwa), jak i nieprawidłową wartość (obciętą do 120 znaków):

Msg 2628, poziom 16, stan 1, Linia x Ciąg lub dane binarne zostałyby obcięte w tabeli „TheDb.Schema.TheTable ”, kolumna„ TheColumn ”. Obcięta wartość:„ … ”. Instrukcja została zakończona.

Odpowiedź

Ostatecznie nie mogłem znaleźć sposobu na uzyskanie informacji o kolumnie bez ich samodzielnego pisania.

Ten komunikat o błędzie został wygenerowany przez DBD::ODBC , możesz też użyć sys.columns (max_length) (po prostu nie wiem jak).

Użyłem takiego kodu na mojej liście kolumn, aby uzyskać listę tablic z dwoma elementami: COLUMN_NAME i MAX_LENGTH (udokumentowane w DBI column_info() ).

my @max_lengths = map [ @{$_->fetchall_arrayref->[0]}[3,6] ] , map $dbh_mssql->column_info("database", "dbo", $dest_table, $_) , @col_mssql ; 

Następnie złapałem wyjątki na INSERT i wydrukowałem coś pożytecznego. W tym przykładzie @$row to dane wysłane do 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; } 

Zagłosuj również i zagłosuj za drugą odpowiedzią

Komentarze

  • I nie ' nie wstawiłem żadnego kodu odwołującego się do sys.columns, ponieważ nie miałem absolutnie pojęcia, jakiego kodu obecnie używasz do ” automagicznie ” generuj zapytania. Naprawdę nie ' nie jest zbyt skomplikowane, jakbym mógł się domyślić, jeśli chodzi o włączenie do kodu niż SELECT name, object_id, max_length FROM sys.columns;. Ponieważ masz już kod automagiczny, który musi to robić – lub coś bardzo podobnego – nie ' myślę, że przykład był potrzebny.
  • I ' Nie wiem, jak sys.columns działa z dwiema kolumnami, które mają takie same name. Co więcej, działało przy użyciu biblioteki, a nie sys, dlaczego miałbym to wybrać jako wybraną odpowiedź? Microsoft SQL doesn't have x, do y instead to ważny wkład, ale jeśli Twój y jest gorszy od mojego y, ja ' mam zamiar zrobić coś innego i oznaczyć to jako wybrane.
  • Twoje pytanie dotyczyło zasadniczo tego, jak mam się dowiedzieć, która kolumna generuje błąd (prawdopodobnie , więc możesz naprawić to jedno miejsce, zamiast przeprojektowywać rozwiązanie). Powiedziałem ci, gdzie szukać: sys.columns. To jest dokładnie miejsce, w którym należy szukać, aby porównać długości kolumn źródłowych z długością kolumn docelowych. Jak to zrobisz, zależy od Ciebie. Nie ' nie powiedziałem ci, jak naprawić kod, ponieważ nie mam absolutnie pojęcia, jak generowane jest zapytanie automagiczne, więc, jak powiedziałem, nie miałem pojęcia, jak aby dodać określenia długości do dowolnego zapytania, które już miałeś.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *