web-dev-qa-db-ja.com

変数から8000文字を超えるSQLステートメントを実行する方法は?

小さな小さなクエリには次のコードを使用できます。

DECLARE @sql VARCHAR(8000)
SET @sql = 'SELECT * FROM myTable'
Exec @sql

上記の方法は、特に一度変更を加えてどこにでも反映させる必要がある場合に、大量のコードを維持するために非常に役立ちます。

私の問題は、@ sql変数にフィードするクエリ(1つのクエリだけです)が25以上のテーブル結合を使用し、それらの一部は一時テーブル変数で使用され、複雑な操作が組み込まれているため、8000文字をはるかに超えることです。

TEXTデータ型を使用してこのクエリを保存したかったのですが、MSDNはMicrosoftがText、NTextおよびImageデータ型を次のバージョンから削除することを計画しているという警告メッセージを表示します。今後もコードが実行されることを願っています。

このクエリを別のファイルに保存することを考えましたが、テーブル変数と他のプロシージャ固有のパラメータで結合を使用するため、これが可能かどうか疑問です。

大きなクエリを変数に保存し、プロシージャで複数回実行する方法を教えてください。

20
Rachcha

SQL Server 2008以降を使用している場合は、VARCHAR(MAX)を使用できます

DECLARE @sql VARCHAR(MAX)
16
Andrea Colleoni

問題は暗黙的な変換にあります。

連結しているUnicode/nChar/nVarCharの値がある場合、SQL Serverは暗黙的に文字列をVarChar(8000)に変換します。残念ながら、文字列が切り捨てられたり、データが既にそのために切り捨てられました!

長い文字列(または長いと思われる文字列)を連結する場合always文字列構築をCASTで事前連結します( '' nVarChar(MAX))のように:

SET @Query = CAST('' as nVarChar(MAX))--Force implicit conversion to nVarChar(MAX)
           + 'SELECT...'-- some of the query gets set here
           + '...'-- more query gets added on, etc.

これがSQL Serverのしくみであると考えるのは、どんなに苦痛で恐ろしいことでしょう。 :(

複数の変数を使用してコードを複数のSET/SELECT割り当てに分割するというWeb上の他の回避策を知っていますが、上記のソリューションを考えるとこれは不要です。

最大4000文字に達した人にとっては、おそらくUnicodeがあり、nVarChar(4000)に暗黙的に変換されたためでした。

説明:
舞台裏で起こっていることは、あなたが割り当てている変数が(MAX)を使用していても、SQL Serverは最初に割り当てている値の右側を評価し、デフォルトでnVarChar(4000)またはVarCharになります(8000)(連結する内容に応じて)。値の計算が完了した後(および値を切り捨てた後)、変数に割り当てるときに値を(MAX)に変換しますが、それまでには遅すぎます。

24
MikeTeeVee
DECLARE @sql VARCHAR(max)
SET @sql = 'SELECT * FROM myTable'
Exec @sql

注意:

Print(@sql)

最初の8000文字のみを表示します!

6
Xtian11

問題は、文字列にデフォルトで8000個のシンボルが制限されているためです。これを防ぐには、(N)VARCHAR(MAX)に変換する必要があります

DECLARE @sql VARCHAR(8000)
        SET @sql = CAST('SELECT * FROM myTable' AS VARCHAR(MAX))
--Check length of variable
 PRINT 'Length is: '+CAST(LEN(@sql) AS VARCHAR)+ 'symbols'
        Exec @sql
4
Dalex

状況を非常によく説明しているこの投稿の回答をお読みください: SQL NVARCHAR and VARCHAR Limits

  1. 文字列の長さxが4000文字未満の場合、文字列はnvarchar(x)に変換されます
  2. 長さyが4000〜8000の場合、varchar(y)
  3. 長さが8000文字を超える場合、nvarchar(max)は最大2GBを保存できます。

問題はnvarchar(max) + varchar(y) = nvarchar(max) + nvarchar(4000); yが4000より大きく8000より小さい場合、SQLはvarchar(y)nvarchar(y)またはnvarchar(4000)に変換し、文字列を切り捨てます!

3
BD01

使用する

EXEC
(
  '
   --your sql script here
  '
)
3
Thit Lwin Oo

さて、私はこれまで(SQL 2005で)実行しましたが、次の2つのオプションがあることを伝えることができます。

1-テキストタイプのパラメーターを取ることができるsys.sp_sqlexecストアドプロシージャを使用します(これは、IMOの方法です)。警告を気にしないでください。 SQL 2008ではntextが引き続きサポートされており、そこでvarchar(max)を行うと動作します。したがって、基本的に、2008年を使用している場合、テキストソリューションとvarchar(max)の両方が機能するため、変更する時間があります=-)。ただし、2012年にはvarchar(max)のみが機能するため、アップグレードする前に変更する必要があります。

2-(これは最初にやったことです)この投稿を確認してください: http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=52274 「Kristen」というユーザーの言うことを実行します。私にとって魅力のように働いた。空の文字列に事前設定することを忘れないでください。あなたが私の投稿を理解していれば、SQL 2008以降ではこれを行うのはばかげていることを知っています。

2
Gaspa79

あなたがそれをしている途中でこれに対する解決策はありません。 2012年現在のMsSqlは、たとえば、Ntextをサポートしており、変数で8000文字を超えることができます。これを解決する方法は、反復可能なテーブルに複数の変数または複数の行を作成することです。

せいぜいMsSqlバージョンでは、変数の最大サイズは、これが入力された時点の最新バージョンで8000文字です。したがって、たとえば80,000文字の文字列を処理する場合。データをそれぞれ8000文字の10個の変数(8000 x 10 = 80,000)に解析するか、変数を細かく切り刻んでLongTable(Bigstring Varchar(8000))というテーブルに入れることができます。 ID値。同じ順序でデータを取得できます。

試みている方法は、現在MsSqlでは機能しません。

動作するがお勧めできないもう1つのわかりにくいオプションは、コマンドシェルコマンドを使用してファイルを読み書きすることにより、変数をテキストファイルに保存することです。次に、8000文字を超えるスペースを使用できます。これは、上記の他の方法よりも遅く、安全性も低くなります。

1
RobPrell

私は同じ問題を抱えていて、文字列が切り捨てられています。 sp_executesqlステートメントを複数回実行できることを学びました。

私のコードブロックは4k/Maxの制限を十分に超えていたため、次のような小さなチャンクに分割しました。

set @statement = '                                                                                      
update pd                               
set pd.mismatchtype = 4                             
  FROM [E].[dbo].[' + @monthName + '_P_Data] pd                             
  WHERE pd.mismatchtype is null '                                                                               
exec sp_executesql @statement                               


set @statement = 'Select * from xxxxxxx'
exec sp_executesql @statement

set @statement = 'Select * from yyyyyyy '
exec sp_executesql @statement

end

したがって、各チャンク自体がサイズ制限内にある限り、各セット@Statementはvarchar(max)を持つことができます(スペース節約のために、この例では実際のコードを切り取ります)

0
Eric King
ALTER PROCEDURE [dbo].[spGetEmails]
AS
BEGIN
    SET NOCOUNT ON;
    -- Insert statements for procedure here

    declare @p varbinary(max)
set @p = 0x
declare @local table (col text)

SELECT   @p = @p + 0x3B + CONVERT(varbinary(100), Email)
 FROM tbCarsList
 where email <> ''
 group by email
 order by email

 set @p = substring(@p, 2, 10000000)

 insert @local values(cast(@p as varchar(max)))
 select   col from @local


END
0
Heta77

印刷前にキャストに変換し、データ型を変更します。

PRINT CAST(@sql AS NTEXT)

今、試してみてください。

0
Prashant Patel

同じ問題がありました。 21,000文字を超えるSQLがあります。何らかの理由で、

Declare @SQL VARCHAR(MAX)

EXEC(@SQL) 

いくつかの問題を思い付くでしょう

最終的に複数の変数に均等に分割する必要があり、それが機能しました。

    Declare @SQL1 VARCHAR(MAX) = 'First Part'
    Declare @SQL2 VARCHAR(MAX) = 'Second  Part'
    Declare @SQL3 VARCHAR(MAX) = 'Third Part'
    Declare @SQL4 VARCHAR(MAX) = 'Fourth Part'

    Set @SQL= @SQL1 + @SQL2 + @SQL3 + @SQL4

    EXEC(@SQL)
0
Amit