SQL Server Insert Into - Comment identifier la colonne à l'origine de l'erreur de troncature

11

J'ai une procédure stockée qui insère 650 champs dans une table. L'insertion échoue avec une erreur de troncature.

C'est simple

INSERT INTO
SELECT (a bunch of fields) 
FROM (a bunch of tables)

Voici le message d'erreur:

Msg 8152, niveau 16, état 14, procédure DSP_Procedure, ligne 1075 La chaîne ou les données binaires seraient tronquées.

Existe-t-il un moyen rapide d'identifier le champ à l'origine de l'erreur de troncature?

Le fait que l'instruction select à insérer dans la table comporte 650 champs rend difficile d'identifier exactement quel champ est à l'origine de l'erreur de troncature.

Je pense que je peux peut-être commenter des blocs de champs à la fois afin que le SP n'insère que 100 champs à la fois, puis exécuter le SP 6 ou 7 fois jusqu'à ce que je puisse au moins me limiter à un groupe de 100 champs qui contiendra le champ à l'origine de l'erreur de troncature.

Alternativement, je pense que je peux peut-être simplement SELECT INTOune nouvelle table, puis comparer les longueurs de données de la table avec les longueurs de données de la table cible dans laquelle j'essaie d'insérer dans mon SP pour voir quel champ contient une longueur de champ plus longue que prévu. ..

J'utilise SQL Server 2014.

Des alternatives plus simples?

Juan Velez
la source
1
Je voudrais aller à INFORMATION_SCHEMA.COLUMNS et comparer les types de données à ceux que vous essayez d'insérer. Malheureusement, SQL Server n'a pas de types de données dynamiques pour la déclaration de variables comme ORACLE.
MguerraTorres
2
Je voudrais utiliser votre deuxième option, insérer dans une nouvelle table (ou #temp) puis comparer les longueurs de colonne. Ou vous pouvez envelopper LEN () autour de toutes les colonnes de la sélection, puis demander à une requête externe de faire un MAX () pour chaque ... qui vous donnera la plus grande longueur de texte pour les champs. Bien sûr, cela suppose que c'est un champ de caractères qui vous pose des problèmes. Vous n'utilisez pas smalldatetime ou tinyint?
Jonathan Fite
1
J'irais avec l'approche "Select Into" et comparerais les longueurs des colonnes, oui. Peut-être avec "WHERE 1 = 0" pour que la table ne contienne aucune ligne. Gênant si votre SELECT n'inclut pas de noms uniques pour les colonnes sélectionnées. Je formate les longues listes de colonnes comme une ligne de script par colonne, puis le nom de la colonne "AS" sur la ligne suivante si nécessaire, et une ligne vierge après quatre colonnes pour faciliter le maintien de la place dans la liste. Cela prend également en charge la sélection de nombreuses lignes et l'utilisation de Ctrl + K Ctrl + C pour les transformer en commentaires, de sorte que vous pouvez attaquer l'opération d'insertion de cette façon, mais les colonnes omises devraient être annulables.
Robert Carnegie

Réponses:

3

Si vous utilisez SQL Server 2016 (SP2, CU6 ou plus récent), une option consiste à activer l'indicateur de trace 460, par exemple (QUERYTRACEON 460). La sortie indiquera la colonne et les données incriminées.

Consultez cet article pour plus de détails. https://www.brentozar.com/archive/2019/03/how-to-fix-the-error-string-or-binary-data-would-be-truncated/

Si vous ne vous souciez pas de la troncature, vous pouvez utiliser SET ANSI_WARNINGS OFFpour ignorer ce type de troncature.

user14472
la source
9

Malheureusement, vous avez rencontré une "fonctionnalité" assez ancienne . Il y a eu un ticket Connect ouvert depuis 2008, et depuis près de dix ans, cela n'a pas été suffisamment important pour justifier une correction.

La solution de contournement norme est, comme vous avez compris, un select into...suivi en comparant les métadonnées de table. Une autre possibilité est la recherche binaire dans la colonne incriminée, mais c'est aussi un travail manuel. Il existe des hacks pour la comparaison des métadonnées, mais il n'existe pas de solution simple et élégante. Peut-être que certains outils tiers seraient utiles, mais je n'en suis pas conscient.

vonPryz
la source
1

L'utilisation de (QUERYTRACEON 460) n'a pas fonctionné pour moi lors de sa mise à la fin de ma requête.

Je l'ai allumé au niveau DB et cela a fonctionné:

DBCC TRACEON(460, -1);
GO

Mais, assurez-vous de le désactiver une fois que vous avez trouvé et résolu le problème, ne le laissez pas allumé!

DBCC TRACEOFF(460, -1);
GO
Taylor Brown
la source