web-dev-qa-db-fra.com

Comment puis-je identifier la ou les colonnes responsables de la "chaîne ou des données binaires seraient tronquées".

Je génère automatiquement des requêtes avec du code que j'ai écrit dans SELECT à partir d'une base de données Pg distante et que j'insère dans une base de données SQL Server locale. Cependant, l'un d'eux génère cette erreur:

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

[Microsoft] [Pilote ODBC SQL Server] [SQL Server] L'instruction est terminée. (SQL-01000) à.\Insert.pl ligne 106.

Comment savoir quelle colonne génère cette erreur et n'a pas la longueur de l'entrée? Existe-t-il un moyen de le faire sans deviner par force brute tous les varchar?

32
Evan Carroll

En fin de compte, je ne pouvais pas trouver un moyen d'obtenir les informations de la colonne sans les écrire moi-même.

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

J'ai utilisé du code comme celui-ci sur ma liste de colonnes pour obtenir une liste de tableaux avec deux éléments, 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, j'ai intercepté les exceptions sur INSERT et imprimé quelque chose d'utile. 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;
}

Aussi, veuillez voter et voter pour l'autre réponse

1
Evan Carroll

Non, il n'est enregistré nulle part. Allez voter et présentez votre analyse de rentabilisation; cela 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 d'abord dans le délai SQL Server 2000 ou 2005), puis à nouveau sur le nouveau système de rétroaction:

Et maintenant, il est livré dans les versions suivantes:

Dans le tout premier CTP public de SQL Server 2019, il n'apparaît que sous l'indicateur 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) à l'avenir, bien que vous puissiez le contrôler via une nouvelle configuration de portée de base de données VERBOSE_TRUNCATION_WARNINGS.

Voici 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
Chaîne ou des données binaires seront tronquées.
La déclaration est terminée.

Maintenant, sur les serveurs CTP SQL Server 2019, avec l'indicateur de trace activé:

DBCC TRACEON(460);
GO

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

Le résultat montre le tableau, la colonne et le ( tronqué , pas plein ) 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'.
La déclaration est terminé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 réellement extraire la longueur maximale de sys.columns, Ainsi que le nom que vous devez y obtenir de toute façon , puis en appliquant LEFT(column, max_length) ou l'équivalent de PG. Ou, puisque cela signifie simplement que vous perdrez silencieusement des données, allez déterminer quelles colonnes sont incompatibles et corrigez les colonnes de destination afin qu'elles tiennent toutes les données de la source. Étant donné l'accè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.

37
Aaron Bertrand

Si vous avez accès à l'exécution Assistant d'importation et d'exportation 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 à partir de SQL Client à l'aide de votre requête comme source de données dans la table de destination.

Avant d'exécuter l'importation, vous pouvez consulter le mappage des données et il vous indiquera quelles colonnes ont des types de champ incohérents. Et si vous exécutez la tâche d'importation, il vous indiquera quelles colonnes n'ont pas pu être importées.

Exemple d'avertissement de validation:

Avertissement 0x802092a7: Tâche de flux de données 1: une troncature peut se produire en raison de l'insertion de données de la colonne de flux de données "NARRATIVE" d'une longueur de 316 dans la colonne de base de données "NARRATIVE" d'une longueur de 60. (Assistant d'importation et d'exportation SQL Server)

2
bubbassauro

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 incluent 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 les données binaires seraient tronquées dans le tableau "TheDb.TheSchemaTheTable", colonne "TheColumn". Valeur tronquée: '...'. La déclaration est terminée.

1
Alexei