Comment identifier la ou les colonnes responsables de “ Les données de chaîne ou binaires seraient tronquées. ”

Je génère automatiquement des requêtes avec du code que jai écrit dans SELECT à partir dune base de données Pg distante, et je les insère dans une base de données SQL Server locale. Cependant, lun deux génère cette erreur:

[Microsoft] [Pilote ODBC SQL Server] [SQL Server] Les données de chaîne ou binaires seraient tronquées. (SQL-22001) [létat était maintenant 22001 01000]

[Microsoft] [Pilote ODBC SQL Server] [SQL Server] Linstruction a été terminée. (SQL-01000) à. \ Insert.pl ligne 106.

Comment puis-je trouver quelle colonne génère cette erreur et na pas la longueur du saisir? Y a-t-il un moyen de faire cela sans deviner par la force brute tous les varchar?

Réponse

Non, il nest enregistré nulle part. Allez voter et exposez votre business case; ceci fait partie de la longue liste de choses qui devraient être corrigées dans SQL Server.

Cela a été demandé il y a des années sur Connect (probablement dabord dans la période SQL Server 2000 ou 2005), puis à nouveau sur le nouveau système de commentaires:

Et maintenant, il a été livré dans les versions suivantes:

Dans le tout premier CTP public de SQL Server 2019, il napparaît que sous lindicateur de trace 460. Cela semble un peu secret, mais il a été publié dans ce livre blanc Microsoft . Ce sera le comportement par défaut (aucun indicateur de trace requis) à lavenir, bien que vous puissiez le contrôler via une nouvelle configuration de portée de base de données VERBOSE_TRUNCATION_WARNINGS.

Ici est un exemple:

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

Résultat dans toutes les versions prises en charge avant SQL Server 2019:

Msg 8152, niveau 16, état 30, ligne 5
La chaîne ou les données binaires seraient tronquées.
Linstruction a été terminée.

Maintenant, sur les CTP SQL Server 2019, avec lindicateur de trace activé:

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

Le résultat affiche le tableau, la colonne et le ( tronqué , pas full ) valeur:

Msg 2628, Niveau 16, état 1, ligne 11
Les données de chaîne ou binaires seraient tronquées dans la table « tempdb.dbo.x », colonne « a ». Valeur tronquée: « f ».
Linstruction a été arrêtée.

Jusquà ce que vous puissiez passer à une version / CU prise en charge, ou passer à Azure SQL Database, vous pouvez modifier votre Code « automagic » pour extraire réellement la longueur max de sys.columns, ainsi que le nom auquel vous devez quand même y arriver, puis appliquer LEFT(column, max_length) ou quel que soit léquivalent de PG. Ou, puisque cela signifie simplement que vous perdrez silencieusement des données, allez déterminer quelles colonnes ne correspondent pas et corriger les colonnes de destination afin quelles correspondent à toutes les données de la source. Étant donné laccès aux métadonnées aux deux systèmes et le fait que vous « écrivez déjà une requête qui doit automatiquement correspondre aux colonnes source -> destination (sinon cette erreur ne serait pas votre plus gros problème), vous ne devriez pas avoir à faire de force brute. deviner du tout.

Réponse

Si vous avez accès à l Assistant dimportation et dexportation SQL Server à partir de SQL Server Management Studio (cliquez avec le bouton droit sur la base de données> Tâches> Importer des données …), créez une tâche qui importe depuis SQL Client en utilisant votre requête comme source de données vers la table de destination.

Avant dexécuter limportation, vous pouvez examiner le mappage des données et il vous indiquera quelles colonnes ont des types de champs incohérents. Et si vous exécutez la tâche dimportation, elle vous indiquera quelle (s) colonne (s) na pas pu être importée.

Exemple davertissement de validation:

Avertissement 0x802092a7: Tâche de flux de données 1: une troncature peut se produire en raison de linsertion de données de la colonne de flux de données « NARRATIVE » avec une longueur de 316 à la colonne de base de données « NARRATIVE » avec une longueur de 60. (Assistant dimportation et dexportation SQL Server)

Réponse

Enfin Microsoft a décidé de fournir des informations utiles pour String or binary would be truncated à partir de SQL Server 2016 SP2 CU, SQL Server 2017 CU12 et dans SQL Server 2019.

Les informations inclut désormais à la fois la colonne du tableau incriminé (nom complet) et la valeur incriminée (tronquée à 120 caractères):

Msg 2628, Niveau 16, État 1, Ligne x Chaîne ou données binaires seraient tronquées dans la table « TheDb.TheSchema.TheTable « , colonne » TheColumn « . Valeur tronquée: » … « . Linstruction a été terminée.

Réponse

En fin de compte, je nai pas pu trouver un moyen dobtenir les informations de la colonne sans lécrire moi-même.

Ce message derreur a été généré par DBD::ODBC , vous pouvez également utiliser sys.columns (max_length) (je ne sais pas comment faire).

Jai utilisé un code comme celui-ci sur ma liste de colonnes pour obtenir une liste de tableaux avec deux éléments, le COLUMN_NAME et MAX_LENGTH (documenté dans DBI column_info() ).

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

Ensuite, jai attrapé les exceptions sur INSERT et jai imprimé quelque chose dutile. Dans cet exemple, @$row correspond aux données envoyées à 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; } 

Veuillez également voter et voter pour lautre réponse

Commentaires

  • I didn ‘ t mettre un code référençant sys.columns car je navais absolument aucune idée du code que vous utilisez actuellement pour  » générer automatiquement  » vos requêtes. Il ny a vraiment pas ‘ t beaucoup plus complexe que je pourrais imaginer à incorporer dans votre code que SELECT name, object_id, max_length FROM sys.columns;. Puisque vous avez déjà du code automagique qui doit faire cela – ou quelque chose de très similaire – je nai ‘ pas pensé quun exemple était nécessaire.
  • Je ‘ Je ne sais pas comment sys.columns fonctionne avec deux colonnes qui ont le même name. De plus, jai fait fonctionner la chose en utilisant la bibliothèque plutôt que sys, pourquoi devrais-je en faire la réponse choisie? Microsoft SQL doesn't have x, do y instead est une contribution valide, mais si votre y est inférieur à mon y, je ‘ je vais faire quelque chose de différent et le marquer comme choisi.
  • Votre question était, essentiellement, comment savoir quelle colonne générait lerreur (vraisemblablement , vous pouvez donc corriger ce point, au lieu de réorganiser la solution). Je vous ai dit où chercher: sys.columns. Cest exactement là que vous devriez regarder pour comparer les longueurs de vos colonnes source avec les longueurs de colonne de destination. Comment vous faites cela dépend de vous. Je nai ‘ t vous dire comment corriger votre code, car je nai absolument aucune idée de la façon dont votre requête automagique a été générée au départ, donc, comme je lai dit, je navais aucune idée de comment pour ajouter les déterminations de longueur à nimporte quelle requête que vous aviez déjà.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *