0

SQL Server 2008で誤解を招くエラーに遭遇しましたが、私に何が起こっているのかを誰かが説明できるでしょうか。

私は次のようなストアドプロシージャを持っています:

declare @cross_reference table (
      context    varchar(20)    not null
    , value1     varchar(10)    not null
    , value2     varchar(10)    not null
)

insert into @cross_reference values ('map', 'from_value', 'to_value')
insert into @cross_reference values ('map', 'from_value', 'to_value')
insert into @cross_reference values ('map', 'from_value_xxxxx', 'to_value_xxxxxxx')

select 
    t1.field1
    , t1.field2
    , xref.value2
from table_1 t1
inner join table_2 t2 on t2.id = t1.id
left join @cross_reference xref on xref.context = 'map' and xref.value1 = t2.map_id 

実際のストアドプロシージャはもっと複雑ですが、これが要点です。

SPを実行すると、「文字列またはバイナリデータが切り捨てられる」というエラーが発生する前に、大量の出力行が表示されます。エラー内の特定の行参照は、上記のメインSELECTステートメントのどこかを指していますが、しばらくデバッグした後、最初に相互参照に入力した値が大きすぎることがわかり、それで修正されました。

しかし、私の質問は次のとおりです。

  • SQL Serverは、相互参照行の挿入を完了せずに、メインのSELECTステートメントをどのように実行しましたか?ある種の遅延処理はありますか?テーブル変数の遅延読み込み?

  • いったいなぜ「文字列またはバイナリデータが切り捨てられる」というメッセージが実際に発生している場所を指していないのでしょうか。それとも私はそれを間違っていますか?

ありがとう、レイ

編集

これは、テーブル変数へのLEFT JOINと関係があり、その列はいずれもWHERE句に含まれていないと思います。SQL Serverは、必要になるまで(INNER JOINが完了した後)テーブルの準備を残しているようで、その時点で、結果セットの大部分をSELECTの準備ができているときにエラーが発生しました。

@cross_referenceに正常に挿入された値が、返される結果セットに表示されることにも気づきました。大きすぎるために挿入に失敗した行はNULLを表示するだけです。

4

2 に答える 2

1

エラーが発生したからといって、ストアドプロシージャの進行が停止することはありません。デフォルトでは、クエリの処理が完了するまでSSMSに結果グリッドが表示されるため、エラーメッセージは表示されません。

これは、エラーメッセージに切り替える前の10秒間の結果を示しています。

RAISERROR('Error',16,1)
select top 1000 * from sys.objects so1,sys.objects so2,sys.objects so3
WAITFOR DELAY '00:00:10'

エラーが発生した場合にストアドプロシージャを早期に終了させたい場合は、早期にベイルアウトする必要があります。挿入物を次のように書き直すことができます。

declare @cross_reference table (
      context    varchar(20)    not null
    , value1     varchar(10)    not null
    , value2     varchar(10)    not null
)

insert into @cross_reference (context,value1,value2)
values ('map', 'from_value', 'to_value'),
       ('map', 'from_value', 'to_value'),
       ('map', 'from_value_xxxxx', 'to_value_xxxxxxx');
if @@ERROR !=0 or @@ROWCOUNT !=3 return

または、行数がわからない場合は、条件を次のように変更します。@@ROWCOUNT = 0

(または、もちろん、TRY/CATCHを使用しますが、私はまだそれらを使用して多くのコードを記述していないので、例をノックアウトすることはできません)

現在のコードでは、各挿入が独立しているため、機能する挿入と機能しない挿入はエラーメッセージを生成します。次に、最終的なクエリの処理を続行します。テーブルはLEFTJOINで使用されるため、もちろん、テーブル変数に行が存在するかどうかは、最終的なクエリには関係ありません。

于 2011-06-27T12:48:39.560 に答える
0

あなたが説明したことを正確に再現することはできません。テーブルvarへのデータの挿入に焦点を当てて言うと、ANSI_WARNINGSがONの場合、挿入の時点でエラーが発生するはずです。

すなわち

SET ANSI_WARNINGS ON -- Gives the truncation error 
DECLARE @T1 TABLE (value1 varchar(10) not null)
INSERT @T1 VALUES ('1234567890ABC')

SET ANSI_WARNINGS OFF -- Does not give the truncation error. "1234567890" will be inserted
DECLARE @T1 TABLE (value1 varchar(10) not null)
INSERT @T1 VALUES ('1234567890ABC')

接続に対してANSI_WARNINGSをオンまたはオフにしますか?

于 2011-06-27T11:15:26.663 に答える