web-dev-qa-db-ja.com

「文字列またはバイナリデータが切り捨てられる」のはなぜより説明的なエラーではないのですか?

開始:このエラーの意味を理解しています-インスタンスを解決しようとはしていません。

このエラーのトラブルシューティングは非常に難しいことで有名です。100列幅のテーブルに100万行を挿入した場合、エラーの原因となっている行の列を特定する方法が事実上ないため、プロセスを変更して1行を挿入する必要があります。一度に、そしてどれが失敗するかを見てください。穏やかに言えば、それは苦痛です。

エラーがこのように見えない理由はありますか?

String or Binary data would be truncated
Error inserting value "Some 18 char value" into SomeTable.SomeColumn VARCHAR(10)

これにより、テーブル構造自体ではなくても、値の検索と修正がはるかに簡単になります。テーブルデータの表示がセキュリティ上の懸念事項である場合は、試行された値の長さや失敗した列の名前を指定するなど、一般的なものでしょうか。

25
SqlRyan

MS Connectには、これに対するオープンな「機能リクエスト」があることが判明しました。機能の変更をご希望の場合は、投票することをお勧めします。

https://connect.Microsoft.com/SQLServer/feedback/details/339410/

追加:

実際には、2005年のユーコンの開発以来傑出したこの同じ機能(名前は不十分ですが)に対する別の要求があるようです。

https://connect.Microsoft.com/SQLServer/feedback/details/125347/

2016年の更新

Microsoftは、このバグの本当の年齢の証拠を削除しようとしたようです。けっこうだ。ここにアーカイブされている 古いサイトを見つけてください。

15
SqlRyan

どこにも受け入れられる答えが見つからなかった後、私は次のことを思いついた:

  1. 問題の原因となっているクエリを取得します(ソースがない場合はSQLプロファイラーを使用することもできます)
  2. 基本的にSELECTとFROMの部分が残るまで、すべてのWHERE句とその他の重要でない部分を削除します。
  3. WHERE 0 = 1を追加します(これにより、テーブル構造のみが選択されます)
  4. FROM句の直前にINTO [MyTempTable]を追加します

あなたは次のようなものになるはずです

SELECT
 Col1, Col2, ..., [ColN]
INTO [MyTempTable]
FROM
  [Tables etc.]
WHERE 0 = 1

これにより、DBにMyTempTableというテーブルが作成され、ターゲットのテーブル構造と比較して、それらの違いを確認できます。つまり、両方のテーブルの列を比較できます。

編集:元のテーブルとMyTempTableの各列のデータ型と列サイズを比較して、それらがどこで異なるかを確認できます。新しいテーブルのすべての列名は古いものと同じになり、データ型とサイズは問題のある列がある場合を除いて同じです。つまり、このクエリを使用すると、SQLは、ソーステーブルから可能な最大のエントリを処理するのに十分な大きさの列を自動的に作成します。

6
profMamba

閉鎖されたDUPに回答するため、代わりにここで回答します。このパターンは、多少複雑な場合でも使用できますが、アプリケーションを変更したり、プロファイラーを設定して何が起こっているかを確認するのが簡単ではない場合に役立ちます。場合によっては、エラーをAPP自体に伝播するだけで、APPから直接正しい有用なエラーメッセージを確認できます。

このような場合、このソリューションを使用してDBをすばやく確認すると、時間を大幅に節約できます。テンプレートとして保存し、テーブルをすばやく変更して、この問題を解決します。

問題

サンプルテーブル

create table StringTruncation
(A int, B varchar(10), C nvarchar(5), D nvarchar(max), E datetime)

サンプルステートメント

insert StringTruncation values
(1, '0123456789', 'abcdef', 'This overflows on C', GETDATE())

恐ろしい役に立たないエラー

Msg 8152, Level 16, State 4, Line 1
String or binary data would be truncated.
The statement has been terminated.

この例では、オーバーフローする可能性のある2列のみが示されていますが、20列または40列であると想像してください。

ソリューション

-- First move the table out of the way
exec sp_rename StringTruncation, StringTruncation_;

-- cover it with a query
create view dbo.StringTruncation
with schemabinding
as
select
    A,
    convert(Nvarchar(max),B) B,
    convert(Nvarchar(max),C) C,
    D, E
from dbo.StringTruncation_
GO

-- use a trigger to allow INSERTs, with the length checks thrown in
create trigger dbo.trig_ioi_StringTruncation
on StringTruncation
instead of insert
as
set nocount on
declare @offending nvarchar(max)
select TOP 1 @offending = case
    when len(C) > 5 then 'Data too long for Column [C] Size 5: ' + C
    when len(B) > 10 then 'Data too long for Column [D] Size 10: ' + B
    end
from inserted
where len(C) > 5 or len(B) > 10
GO

-- keep good data
if @@rowcount = 0
    insert StringTruncation_
    select * from inserted
else
    raiserror(@offending,16,1)
GO

試して

insert StringTruncation values
(1, '0s123456789', 'abcde', 'This overflows on C', GETDATE())

結果

メッセージ50000、レベル16、状態1、プロシージャtrig_ioi_StringTruncation、行18
列[D]のデータが長すぎますサイズ10:0s123456789

(影響を受ける1行)

ノート

  • UPDATEのミラートリガーが必要です
  • 現在、最初の問題のあるレコード列についてのみレポートします。複数のレコード列を報告することは可能ですが、それは実際には逆効果だと思います。
4
RichardTheKiwi

ソフトウェアシステムの説明的なエラーメッセージは、存在しないのと同じくらい優れています。

これは、DBMSだけでなく、想像できるあらゆる種類のソフトウェアにも当てはまります。

根本的な理由は、「適切な説明エラーメッセージ」の実装に時間がかかりすぎるためだと思います。 「この特定の種類の例外が発生した場合にユーザーが確認したい情報」について考えることに多くの時間を費やすことは、平均的なソフトウェア開発者の文化の一部ではありませんか? 「適切な説明エラーメッセージ」を表示するためのコードを書き留める必要があるプログラマーは、コスト(時間)のみを確認し、メリットは確認しません。

ソフトウェアシステムから受け取った最新のエラーメッセージの1つは、「問題が発生しました。後でもう一度やり直してください」です。冗談じゃない。

0
Erwin Smout

短い答え:それはまさにそれです。

長い回答:行番号と列を表示することには価値がありますが、実際の情報が切り捨てられていることを表示することはおそらく意味がありません。 VARCHAR(10)シナリオでは、おそらく大したことではありませんが、サイズが大きすぎるデータは非常に役立ちます。しかし、うまくいけば、ここに誰もVARCHAR(MAX)が保持できる以上のものを挿入していません;)

0
Kevin Fairchild

マイクロソフトは怠け者ですか?

ちなみに、各行の挿入を個別に試す必要はありません。各テキスト列のmax(len(field))をクエリするだけで、原因であると思われるものから始めます。

0
JC Ford