エラー、文字列、またはバイナリデータは挿入しようとすると切り捨てられます


250

次の行を含むdata.batファイルを実行しています。

Rem Tis batch file will populate tables

cd\program files\Microsoft SQL Server\MSSQL
osql -U sa -P Password -d MyBusiness -i c:\data.sql

data.sqlファイルの内容は次のとおりです。

   insert Customers
            (CustomerID, CompanyName, Phone)
             Values('101','Southwinds','19126602729')

レコードを追加するための同様の行がさらに8行あります。

私はこれを実行するとstart> run> cmd> c:\data.bat、私は、このエラーメッセージが表示されます:

1>2>3>4>5>....<1 row affected>
Msg 8152, Level 16, State 4, Server SP1001, Line 1
string or binary data would be truncated.

<1 row affected>

<1 row affected>

<1 row affected>

<1 row affected>

<1 row affected>

<1 row affected>

また、私は初心者は明らかですが、何をすべきかLevel #、そしてstate #平均値、およびどのように私は前述のようなエラーメッセージを検索します:8152?

回答:


609

gmmastrosの答え@

メッセージが表示されたときはいつでも...

文字列型やバイナリは省略されます

考えてみてください...フィールドは私のデータを保持するのに十分な大きさではありません。

Customersテーブルのテーブル構造を確認します。1つ以上のフィールドの長さが、挿入しようとしているデータを保持するのに十分大きくないことがわかるでしょう。たとえば、Phoneフィールドがvarchar(8)フィールドであり、11文字を入力しようとすると、このエラーが発生します。


16
また、影響を受けるフィールドがトリガーになる可能性があることにも注意してください。うまくいけば、次回これが発生したときに私はこれを覚えています...
ケビン・ポープ

14
どのフィールドが切り捨てられるかをデバッグで確認する方法はありますか?
DailyFrankPeter

このエラーは、固定長を超えると列にデータを保持できなくなるためです。例えば; Firstname nvarchar(5) 5文字を超える数を挿入すると、エラーが発生します
Prakash

26

データ長がフィールド長より短いにもかかわらず、この問題がありました。列のサイズも変更する必要があるメインテーブルのトリガーで満たされた別のログテーブル(監査証跡用)が問題であることがわかりました。


1
ありがとう。鉱山は、tableAのsql列がvarchar(100)であるためです。また、列がvarchar(50)である別のテーブルにも挿入します。
Hnin Htet Htet Aung 2017

1
私の場合も同じ問題が起こりました。トリガー操作が原因でした。
自動操縦:

19

INSERTステートメントの1つで、長すぎる文字列を文字列(varcharまたはnvarchar)列に挿入しようとしています。

INSERTスクリプトを確認しただけでは犯人が明らかでない場合は、エラーメッセージの<1 row affected>発生する行を数えることができます。取得した数に1を加えたものがステートメント番号になります。あなたの場合、エラーを生成するのは2番目のINSERTのようです。


2
私は同じ問題を抱えていますが、どの列がエラーの原因であるかを見つける方法は?
CATIAマトス

@AndréBastos:おそらくあなたはそれを質問として提出することができます(他の誰かがすでにそれを行っていない限り、その場合、どこかですぐに答えが出る可能性があります)。
Andriy M

11

一部のデータがデータベースの列(小)に収まりません。何が悪いのかを見つけるのは簡単ではありません。C#とLinq2Sqlを使用する場合は、切り捨てられるフィールドをリストできます。

最初にヘルパークラスを作成します。

public class SqlTruncationExceptionWithDetails : ArgumentOutOfRangeException
{
    public SqlTruncationExceptionWithDetails(System.Data.SqlClient.SqlException inner, DataContext context)
        : base(inner.Message + " " + GetSqlTruncationExceptionWithDetailsString(context))
    {
    }

    /// <summary>
    /// PArt of code from following link
    /// http://stackoverflow.com/questions/3666954/string-or-binary-data-would-be-truncated-linq-exception-cant-find-which-fiel
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    static string GetSqlTruncationExceptionWithDetailsString(DataContext context)
    {
        StringBuilder sb = new StringBuilder();

        foreach (object update in context.GetChangeSet().Updates)
        {
            FindLongStrings(update, sb);
        }

        foreach (object insert in context.GetChangeSet().Inserts)
        {
            FindLongStrings(insert, sb);
        }
        return sb.ToString();
    }

    public static void FindLongStrings(object testObject, StringBuilder sb)
    {
        foreach (var propInfo in testObject.GetType().GetProperties())
        {
            foreach (System.Data.Linq.Mapping.ColumnAttribute attribute in propInfo.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), true))
            {
                if (attribute.DbType.ToLower().Contains("varchar"))
                {
                    string dbType = attribute.DbType.ToLower();
                    int numberStartIndex = dbType.IndexOf("varchar(") + 8;
                    int numberEndIndex = dbType.IndexOf(")", numberStartIndex);
                    string lengthString = dbType.Substring(numberStartIndex, (numberEndIndex - numberStartIndex));
                    int maxLength = 0;
                    int.TryParse(lengthString, out maxLength);

                    string currentValue = (string)propInfo.GetValue(testObject, null);

                    if (!string.IsNullOrEmpty(currentValue) && maxLength != 0 && currentValue.Length > maxLength)
                    {
                        //string is too long
                        sb.AppendLine(testObject.GetType().Name + "." + propInfo.Name + " " + currentValue + " Max: " + maxLength);
                    }

                }
            }
        }
    }
}

次に、SubmitChangesのラッパーを準備します。

public static class DataContextExtensions
{
    public static void SubmitChangesWithDetailException(this DataContext dataContext)
    {
        //http://stackoverflow.com/questions/3666954/string-or-binary-data-would-be-truncated-linq-exception-cant-find-which-fiel
        try
        {
            //this can failed on data truncation
            dataContext.SubmitChanges();
        }       
        catch (SqlException sqlException) //when (sqlException.Message == "String or binary data would be truncated.")
        {

            if (sqlException.Message == "String or binary data would be truncated.") //only for EN windows - if you are running different window language, invoke the sqlException.getMessage on thread with EN culture
                throw new SqlTruncationExceptionWithDetails(sqlException, dataContext);
            else
                throw;
        }
    }
}

グローバル例外ハンドラーを準備し、切り捨ての詳細をログに記録します。

protected void Application_Error(object sender, EventArgs e)
{
    Exception ex = Server.GetLastError();
    string message = ex.Message;
    //TODO - log to file
}

最後にコードを使用します。

Datamodel.SubmitChangesWithDetailException();

9

追加情報を提供したいだけです:私は同じ問題を抱えていましたが、これはフィールドが受信データに対して十分に大きくなかったためであり、このスレッドはそれを解決するのに役立ちました(上の答えはすべてを明らかにしています)。

しかし、それを引き起こす可能性のある考えられる理由を知ることは非常に重要です。

私の場合、私はこのようなフィールドを持つテーブルを作成していました:

Select '' as  Period, * From Transactions Into #NewTable

したがって、フィールド「期間」の長さがゼロで、挿入操作が失敗しました。受信データの長さである "XXXXXX"に変更しましたが、正しく機能しました(フィールドが6になったため)。

私はこれが同じ問題を持つ人を助けることを願っています:)


7

このエラーが発生する別の状況は次のとおりです。

同じエラーが発生しましたが、その理由は、UNIONからデータを受け取ったINSERTステートメントで、列の順序が元のテーブルと異なっていたためです。#table3の順序をa、b、cに変更すると、エラーが修正されます。

select a, b, c into #table1
from #table0

insert into #table1
    select a, b, c from #table2
    union
    select a, c, b from #table3

7

SQLサーバーでは、次のようにSET ANSI_WARNINGS OFFを使用できます。

        using (SqlConnection conn = new SqlConnection("Data Source=XRAYGOAT\\SQLEXPRESS;Initial Catalog='Healthy Care';Integrated Security=True"))
        {
            conn.Open();

            using (var trans = conn.BeginTransaction())
            {
                try
                {
                    using cmd = new SqlCommand("", conn, trans))
                    { 

                    cmd.CommandText = "SET ANSI_WARNINGS OFF";
                    cmd.ExecuteNonQuery();

                    cmd.CommandText = "YOUR INSERT HERE";
                    cmd.ExecuteNonQuery();

                    cmd.Parameters.Clear();

                    cmd.CommandText = "SET ANSI_WARNINGS ON";
                    cmd.ExecuteNonQuery();

                    trans.Commit();
                    }
                }
                catch (Exception)
                {

                    trans.Rollback();
                }

            }

            conn.Close();

        }

7

同じ問題がありました。列の長さが短すぎました。

あなたにできることはどちらかである増やす長または短縮、データベースに入れたいテキストを。


7

また、Webアプリケーションの表面でこの問題が発生していました。最終的に、同じエラーメッセージが特定のテーブルのSQL更新ステートメントからのものであることがわかりました。

最後にnvarchar、いくつかの特定のケースでは、関連する履歴テーブルの列定義がタイプの元のテーブル列の長さをマップしていないことを理解しました。


4

テーブルの問題のある列のサイズを増やした後でも、同じ問題が発生しました。

tl; dr:対応するテーブルタイプの一致する列の長さも増やす必要がある場合があります。

私の場合、エラーはMicrosoft Dynamics CRMのデータエクスポートサービスに起因しており、CRMデータをSQL Server DBまたはAzure SQL DBに同期できます。

長い調査の結果、データエクスポートサービスではテーブル値パラメーターを使用する必要があると結論付けました。

テーブル値パラメーターを使用すると、一時テーブルや多くのパラメーターを作成せずに、データの複数の行をTransact-SQLステートメントまたはストアドプロシージャや関数などのルーチンに送信できます。

上記のドキュメントでわかるように、テーブルタイプはデータの取り込み手順を作成するために使用されます。

CREATE TYPE LocationTableType AS TABLE (...);
CREATE PROCEDURE dbo.usp_InsertProductionLocation
  @TVP LocationTableType READONLY

残念ながら、テーブルタイプを変更する方法はないため、完全に削除して再作成する必要があります。テーブルには300を超えるフィールド(😱)があるため、テーブルの列定義に基づいて対応するテーブルタイプを簡単に作成できるようにクエリを作成しました([table_name]テーブルの名前に置き換えるだけです)。

SELECT 'CREATE TYPE [table_name]Type AS TABLE (' + STRING_AGG(CAST(field AS VARCHAR(max)), ',' + CHAR(10)) + ');' AS create_type
FROM (
  SELECT TOP 5000 COLUMN_NAME + ' ' + DATA_TYPE
      + IIF(CHARACTER_MAXIMUM_LENGTH IS NULL, '', CONCAT('(', IIF(CHARACTER_MAXIMUM_LENGTH = -1, 'max', CONCAT(CHARACTER_MAXIMUM_LENGTH,'')), ')'))
      + IIF(DATA_TYPE = 'decimal', CONCAT('(', NUMERIC_PRECISION, ',', NUMERIC_SCALE, ')'), '')
      AS field
  FROM INFORMATION_SCHEMA.COLUMNS
  WHERE TABLE_NAME = '[table_name]'
  ORDER BY ORDINAL_POSITION) AS T;

テーブルタイプを更新した後、データエクスポートサービスが再び適切に機能し始めました!:)


2

ストアドプロシージャを実行しようとすると、一部のデータを追加する必要がある列のサイズが、追加するデータよりも短いため、同じ問題が発生しました。

列のデータ型のサイズを大きくするか、データの長さを短くすることができます。


1

このエラーが発生する別の状況は、SQL Server Management Studioです。テーブルに "text"または "ntext"フィールドがある場合、更新するフィールドの種類(ビットや整数など)に関係なく。Studioは「ntext」フィールド全体をロードせず、変更されたフィールドではなくすべてのフィールドも更新するようです。この問題を解決するには、Management Studioのクエリから「テキスト」または「ntext」フィールドを除外します


1
コンマ、ピリオドを追加し、文法エラーを修正して、回答を言い換えることを検討してください。
ジョージパンフィリス

この答えは私を助けました-私のnvarcharフィールドは十分に大きいですが、私はntextフィールドを持っています。Management Studio / SMSSのエラーのようです。
Sha

0

受け入れられた答えの下でのケビン・ポープのコメントは私が必要としたものでした。

私の場合の問題は、更新/挿入トランザクションを監査テーブルに挿入するトリガーがテーブルに定義されていたが、監査テーブルのデータ型が一致しておらずVARCHAR(MAX)、元のテーブルの列VARCHAR(1)が監査テーブルなので、VARCHAR(1)元のテーブル列よりも大きいものを挿入するとトリガーが失敗し、このエラーメッセージが表示されました。


0

いくつかの場所で8Kが割り当てられている別の戦術フィールドを使用しました。ここでは、約50/100のみが使用されます。

declare @NVPN_list as table 
nvpn            varchar(50)
,nvpn_revision  varchar(5)
,nvpn_iteration INT
,mpn_lifecycle  varchar(30)
,mfr            varchar(100)
,mpn            varchar(50)
,mpn_revision   varchar(5)
,mpn_iteration  INT
-- ...
) INSERT INTO @NVPN_LIST 
SELECT  left(nvpn           ,50)    as nvpn
        ,left(nvpn_revision ,10)    as nvpn_revision
        ,nvpn_iteration
        ,left(mpn_lifecycle ,30)
        ,left(mfr           ,100)
        ,left(mpn           ,50)
        ,left(mpn_revision  ,5)
        ,mpn_iteration
        ,left(mfr_order_num ,50)
FROM [DASHBOARD].[dbo].[mpnAttributes] (NOLOCK) mpna

合計1Mのレコードがあり、そのうち28Kをロードしたので、スピードが欲しかった。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.