小さな小さなクエリには次のコードを使用できます。
DECLARE @sql VARCHAR(8000)
SET @sql = 'SELECT * FROM myTable'
Exec @sql
上記の方法は、特に一度変更を加えてどこにでも反映させる必要がある場合に、大量のコードを維持するために非常に役立ちます。
私の問題は、@ sql変数にフィードするクエリ(1つのクエリだけです)が25以上のテーブル結合を使用し、それらの一部は一時テーブル変数で使用され、複雑な操作が組み込まれているため、8000文字をはるかに超えることです。
TEXTデータ型を使用してこのクエリを保存したかったのですが、MSDNはMicrosoftがText、NTextおよびImageデータ型を次のバージョンから削除することを計画しているという警告メッセージを表示します。今後もコードが実行されることを願っています。
このクエリを別のファイルに保存することを考えましたが、テーブル変数と他のプロシージャ固有のパラメータで結合を使用するため、これが可能かどうか疑問です。
大きなクエリを変数に保存し、プロシージャで複数回実行する方法を教えてください。
SQL Server 2008以降を使用している場合は、VARCHAR(MAX)を使用できます
DECLARE @sql VARCHAR(MAX)
連結している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)に変換しますが、それまでには遅すぎます。
DECLARE @sql VARCHAR(max)
SET @sql = 'SELECT * FROM myTable'
Exec @sql
注意:
Print(@sql)
最初の8000文字のみを表示します!
問題は、文字列にデフォルトで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
状況を非常によく説明しているこの投稿の回答をお読みください: SQL NVARCHAR and VARCHAR Limits
nvarchar(x)
に変換されますvarchar(y)
nvarchar(max)
は最大2GBを保存できます。問題はnvarchar(max) + varchar(y) = nvarchar(max) + nvarchar(4000)
; yが4000より大きく8000より小さい場合、SQLはvarchar(y)
をnvarchar(y)
またはnvarchar(4000)
に変換し、文字列を切り捨てます!
使用する
EXEC
(
'
--your sql script here
'
)
さて、私はこれまで(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以降ではこれを行うのはばかげていることを知っています。
あなたがそれをしている途中でこれに対する解決策はありません。 2012年現在のMsSqlは、たとえば、Ntextをサポートしており、変数で8000文字を超えることができます。これを解決する方法は、反復可能なテーブルに複数の変数または複数の行を作成することです。
せいぜいMsSqlバージョンでは、変数の最大サイズは、これが入力された時点の最新バージョンで8000文字です。したがって、たとえば80,000文字の文字列を処理する場合。データをそれぞれ8000文字の10個の変数(8000 x 10 = 80,000)に解析するか、変数を細かく切り刻んでLongTable(Bigstring Varchar(8000))というテーブルに入れることができます。 ID値。同じ順序でデータを取得できます。
試みている方法は、現在MsSqlでは機能しません。
動作するがお勧めできないもう1つのわかりにくいオプションは、コマンドシェルコマンドを使用してファイルを読み書きすることにより、変数をテキストファイルに保存することです。次に、8000文字を超えるスペースを使用できます。これは、上記の他の方法よりも遅く、安全性も低くなります。
私は同じ問題を抱えていて、文字列が切り捨てられています。 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)を持つことができます(スペース節約のために、この例では実際のコードを切り取ります)
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
印刷前にキャストに変換し、データ型を変更します。
PRINT CAST(@sql AS NTEXT)
今、試してみてください。
同じ問題がありました。 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)