@Paulの回答に触発されて、私はいくつかの調査を行い、スタックスペースは連結の数を制限することは事実であり、そのスタックスペースは利用可能なメモリの関数であり、したがって変化することがわかりましたが、次の2つの点も当てはまります。 :
- 追加の連結を単一のステートメントに詰め込む方法があり、かつ
- この方法を使用して、初期スタックスペース制限を超えると、実際の論理制限(変化していないように見える)を見つけることができます
まず、Paulのテストコードを文字列を連結するように調整しました。
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'
DECLARE @S VARCHAR(MAX), @A VARCHAR(MAX) = ''a'';
SET @S = @A';
SET @SQL += REPLICATE(CONVERT(NVARCHAR(MAX), N' + @A'), 3312) + N';';
-- SET @S = @A + @A + @A...
SET @SQL += N'SELECT DATALENGTH(@S) AS [Chars In @S];';
EXECUTE (@SQL);
このテストで、それほど大きくないラップトップ(6 GBのRAMのみ)で実行したときに得られる最高値は次のとおりです。
- SQL Server 2017 Express Edition LocalDBを使用する3311(合計3312文字を返す)(14.0.3006)
- SQL Server 2012 Developer Edition SP4(KB4018073)を使用した3512(合計3513文字を返す)(11.0.7001)
エラー8631が発生する前。
次に、操作が連結の複数のグループを連結するように、括弧を使用して連結をグループ化してみました。例えば:
SET @S = (@A + @A + @A + @A) + (@A + @A + @A + @A) + (@A + @A + @A + @A);
そうすることで、以前の3312および3513変数の制限を大幅に超えることができました。更新されたコードは次のとおりです。
DECLARE @SQL VARCHAR(MAX), @Chunk VARCHAR(MAX);
SET @SQL = '
DECLARE @S VARCHAR(MAX), @A VARCHAR(MAX) = ''a'';
SET @S = (@A+@A)';
SET @Chunk = ' + (@A' + REPLICATE(CONVERT(VARCHAR(MAX), '+@A'), 42) + ')';
SET @SQL += REPLICATE(CONVERT(VARCHAR(MAX), @Chunk), 762) + ';';
SET @SQL += 'SELECT DATALENGTH(@S) AS [Chars In @S];';
-- PRINT @SQL; -- for debug
-- SET @S = (@A+@A) + (@A + @A...) + ...
EXECUTE (@SQL);
(私にとっての)最大値42
は、最初のに使用することで、REPLICATE
グループごとに43の変数を使用762
し、次に2番目のREPLICATE
に使用して、それぞれ43の変数の762グループを使用します。最初のグループは2つの変数でハードコードされています。
出力には、@S
変数に32,768文字があることが示されます。初期グループを(@A+@A+@A)
だけ(@A+@A)
ではなくに更新すると、次のエラーが発生します。
メッセージ8632、レベル17、状態2、行XXXXX
内部エラー:式サービスの制限に達しました。クエリで潜在的に複雑な式を探し、それらを簡略化してみてください。
エラー番号が以前とは異なることに注意してください。現在は8632です。また、SQL Server 2012インスタンスとSQL Server 2017インスタンスのどちらを使用しても、同じ制限があります。
ここでの上限(32,768)が(.NETで)IF の最大容量(最大値は32,767ですが、多くの/ほとんどのプログラミング言語の配列は0ベース)であることはおそらく偶然ではありません。SMALLINT
Int16
0