Sql openquery内で次のようなパラメーターを使用するにはどうすればよいですか?
SELECT * FROM OPENQUERY([NameOfLinkedSERVER], 'SELECT * FROM TABLENAME
where field1=@someParameter') T1 INNER JOIN MYSQLSERVER.DATABASE.DBO.TABLENAME
T2 ON T1.PK = T2.PK
OPENQUERY ドキュメンテーションから、それは次のように述べています:
OPENQUERYは、引数に変数を受け入れません。
回避策については、こちらをご覧ください 記事 .
UPDATE:
提案されているように、以下の記事の推奨事項を含めています。
基本値を渡す
基本的なTransact-SQLステートメントはわかっているが、1つ以上の特定の値を渡す必要がある場合は、次のサンプルのようなコードを使用します。
DECLARE @TSQL varchar(8000), @VAR char(2)
SELECT @VAR = 'CA'
SELECT @TSQL = 'SELECT * FROM OPENQUERY(MyLinkedServer,''SELECT * FROM pubs.dbo.authors WHERE state = ''''' + @VAR + ''''''')'
EXEC (@TSQL)
クエリ全体を渡す
Transact-SQLクエリ全体またはリンクサーバーの名前(または両方)を渡す必要がある場合は、次のサンプルのようなコードを使用します。
DECLARE @OPENQUERY nvarchar(4000), @TSQL nvarchar(4000), @LinkedServer nvarchar(4000)
SET @LinkedServer = 'MyLinkedServer'
SET @OPENQUERY = 'SELECT * FROM OPENQUERY('+ @LinkedServer + ','''
SET @TSQL = 'SELECT au_lname, au_id FROM pubs..authors'')'
EXEC (@OPENQUERY+@TSQL)
Sp_executesqlストアドプロシージャを使用する
多層引用符を回避するには、次のサンプルに類似したコードを使用します。
DECLARE @VAR char(2)
SELECT @VAR = 'CA'
EXEC MyLinkedServer.master.dbo.sp_executesql
N'SELECT * FROM pubs.dbo.authors WHERE state = @state',
N'@state char(2)',
@VAR
文字列を作成したら、OPENQUERYで文字列を実行できます。このルートに進む場合は、セキュリティについて考え、ユーザーが入力したテキストをSQLに連結しないように注意してください!
DECLARE @Sql VARCHAR(8000)
SET @Sql = 'SELECT * FROM Tbl WHERE Field1 < ''someVal'' AND Field2 IN '+ @valueList
SET @Sql = 'SELECT * FROM OPENQUERY(SVRNAME, ''' + REPLACE(@Sql, '''', '''''') + ''')'
EXEC(@Sql)
MSDNページ から:
OPENQUERYは引数に変数を受け入れません
基本的に、これは動的クエリを発行できないことを意味します。サンプルが試みていることを達成するには、これを試してください:
SELECT * FROM
OPENQUERY([NameOfLinkedSERVER], 'SELECT * FROM TABLENAME') T1
INNER JOIN
MYSQLSERVER.DATABASE.DBO.TABLENAME T2 ON T1.PK = T2.PK
where
T1.field1 = @someParameter
明らかに、TABLENAMEテーブルに大量のデータが含まれている場合、これもネットワーク全体に行き渡り、パフォーマンスが低下する可能性があります。一方、少量のデータの場合、これはうまく機能し、exec
アプローチが必要とする可能性のある動的なSQL構築のオーバーヘッド(SQLインジェクション、引用符のエスケープ)を回避します。
実際、これを行う方法を見つけました。
DECLARE @username varchar(50)
SET @username = 'username'
DECLARE @Output as numeric(18,4)
DECLARE @OpenSelect As nvarchar(500)
SET @OpenSelect = '(SELECT @Output = CAST((CAST(pwdLastSet As bigint) / 864000000000) As numeric(18,4)) FROM OpenQuery (ADSI,''SELECT pwdLastSet
FROM ''''LDAP://domain.net.intra/DC=domain,DC=net,DC=intra''''
WHERE objectClass = ''''User'''' AND sAMAccountName = ''''' + @username + '''''
'') AS tblADSI)'
EXEC sp_executesql @OpenSelect, N'@Output numeric(18,4) out', @Output out
SELECT @Output As Outputs
これにより、OpenQueryの実行結果が変数@Outputに割り当てられます。
MSSQL 2012でストアプロシージャをテストしましたが、MSSQL 2008+で動作するはずです。
Microsoftによると、sp_executesql(Transact-SQL):適用対象:SQL Server(SQL Server 2008〜現在のバージョン)、Windows Azure SQL Database(初期リリース〜現在のリリース)。 ( http://msdn.Microsoft.com/en-us/library/ms188001.aspx )
DECLARE @guid varchar(36); select @guid= convert(varchar(36), NEWID() );
/*
The one caveat to this technique is that ##ContextSpecificGlobal__Temp should ALWAYS have the exact same columns.
So make up your global temp table name in the sproc you're using it in and only there!
In this example I wanted to pass in the name of a global temporary table dynamically. I have 1 procedure dropping
off temporary data in whatever @TableSrc is and another procedure picking it up but we are dynamically passing
in the name of our pickup table as a parameter for OPENQUERY.
*/
IF ( OBJECT_ID('tempdb..##ContextSpecificGlobal__Temp' , 'U') IS NULL )
EXEC ('SELECT * INTO ##ContextSpecificGlobal__Temp FROM OPENQUERY(loopback, ''Select *,''''' + @guid +''''' as tempid FROM ' + @TableSrc + ''')')
ELSE
EXEC ('INSERT ##ContextSpecificGlobal__Temp SELECT * FROM OPENQUERY(loopback, ''Select *,''''' + @guid +''''' as tempid FROM ' + @TableSrc + ''')')
--If this proc is run frequently we could run into race conditions, that's why we are adding a guid and only deleting
--the data we added to ##ContextSpecificGlobal__Temp
SELECT * INTO #TableSrc FROM ##ContextSpecificGlobal__Temp WHERE tempid = @guid
BEGIN TRAN t1
IF ( OBJECT_ID('tempdb..##ContextSpecificGlobal__Temp' , 'U') IS NOT NULL )
BEGIN
-- Here we wipe out our left overs if there if everyones done eating the data
IF (SELECT COUNT(*) FROM ##ContextSpecificGlobal__Temp) = 0
DROP TABLE ##ContextSpecificGlobal__Temp
END
COMMIT TRAN t1
-- YEAH! Now I can use the data from my openquery without wrapping the whole !$#@$@ thing in a string.
SELECT field1 FROM OPENQUERY
([NameOfLinkedSERVER],
'SELECT field1 FROM TABLENAME')
WHERE field1=@someParameter T1
INNER JOIN MYSQLSERVER.DATABASE.DBO.TABLENAME
T2 ON T1.PK = T2.PK
動的SQLとOpenQueryを組み合わせます。 (これはTeradataサーバーに送られます)
DECLARE
@dayOfWk TINYINT = DATEPART(DW, GETDATE()),
@qSQL NVARCHAR(MAX) = '';
SET @qSQL = '
SELECT
*
FROM
OPENQUERY(TERASERVER,''
SELECT DISTINCT
CASE
WHEN ' + CAST(@dayOfWk AS NCHAR(1)) + ' = 2
THEN ''''Monday''''
ELSE ''''Not Monday''''
END
'');';
EXEC sp_executesql @qSQL;
次の例では、部門パラメータをストアドプロシージャ(spIncreaseTotalsRpt)に渡し、同時にすべてのOPENQUERYから一時テーブルを作成しています。 TempテーブルはグローバルTemp(##)である必要があるため、インスタンスの外部で参照できます。 exec sp_executesqlを使用すると、部門パラメーターを渡すことができます。
注:sp_executeSQLを使用する場合は注意してください。また、管理者がこのオプションを使用できない場合があります。
これが誰かを助けることを願っています。
IF OBJECT_ID('tempdb..##Temp') IS NOT NULL
/*Then it exists*/
begin
DROP TABLE ##Temp
end
Declare @Dept as nvarchar(20) ='''47'''
declare @OPENQUERY as nvarchar(max)
set @OPENQUERY = 'Select ' + @Dept + ' AS Dept, * into ##Temp from openquery(SQL_AWSPROD01,'''
declare @sql nvarchar(max)= @openquery + 'SET FMTONLY OFF EXECUTE SalaryCompensation.dbo.spIncreaseTotalsRpts ' + '''' + @Dept + '''' + ''')'
declare @parmdef nvarchar(25)
DECLARE @param nvarchar(20)
SET @parmdef = N'@Dept varchar(20)'
-- select @sql
-- Print @sql + @parmdef + @dept
exec sp_executesql @sql,@parmdef, @Dept
Select * from ##Temp
結果
増加部Cnt 0 1 2 3 4 5 6 0.0000 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
自分に合った方法を見つけました。 リンクサーバーがアクセスできるスクラッチテーブルを使用する必要があります。
テーブルを作成し、必要な値を設定してから、リンクサーバーを介してそのテーブルを参照します。
SELECT *
FROM OPENQUERY(KHSSQLODSPRD,'SELECT *
FROM ABC.dbo.CLAIM A WITH (NOLOCK)
WHERE A.DOS >= (SELECT MAX(DATE) FROM KHSDASQL01.DA_MAIN.[dbo].[ALLFILENAMES]) ')