99

次のように、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
4

14 に答える 14

171

OPENQUERYのドキュメントから、次のように述べられています。

OPENQUERY は、その引数に変数を受け入れません。

回避策については、この記事を参照してください。

アップデート:

提案どおり、以下の記事の推奨事項を含めます。

基本値を渡す

基本的な 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
于 2010-07-31T14:48:46.557 に答える
16

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 インジェクション、引用符のエスケープ) を回避できます。

于 2010-07-31T14:47:27.883 に答える
15

文字列を作成したら、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)
于 2010-07-31T14:47:24.837 に答える
4
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.
于 2012-05-04T16:28:00.177 に答える
1
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
于 2014-11-07T11:00:59.627 に答える
1

次の例では、部門パラメーターをストアド プロシージャ (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

于 2014-04-08T17:18:25.637 に答える
0

自分に合う方法を見つけました。ただし、リンク サーバーがアクセスできるスクラッチ テーブルを使用する必要があります。

テーブルを作成し、必要な値を入力してから、リンク サーバーを介してそのテーブルを参照します。

SELECT * 
FROM OPENQUERY(KHSSQLODSPRD,'SELECT *
  FROM ABC.dbo.CLAIM A WITH (NOLOCK)
  WHERE A.DOS >= (SELECT MAX(DATE) FROM KHSDASQL01.DA_MAIN.[dbo].[ALLFILENAMES]) ')
于 2015-08-12T23:40:54.283 に答える
-1

この方法で試してみてください。簡単に動作するはずです。WHERE 句で、列名と等号の後に:- 2 つの単一引用符、検索値、3 つの単一引用符を追加します。ブラケットを閉じます。

SELECT * FROM OPENQUERY([NameOfLinkedSERVER], 'SELECT * FROM TABLENAME where field1=''your search value''') T1 INNER JOIN MYSQLSERVER.DATABASE.DBO.TABLENAME T2 ON T1.PK = T2.PK

于 2020-11-19T21:06:09.560 に答える
-2

上記の@Tuan Zaidiの例に基づいた簡単な例は、最も簡単に思えました。OPENQUERY の外側でフィルターを実行できることを知りませんでした...とても簡単です!

ただし、私の場合、変数に詰め込む必要があったため、追加のサブクエリレベルを作成して単一の値を返しました。

SET @SFID = (SELECT T.Id FROM (SELECT Id,  Contact_ID_SQL__c  FROM OPENQUERY([TR-SF-PROD], 'SELECT Id,  Contact_ID_SQL__c FROM Contact') WHERE Contact_ID_SQL__c = @ContactID) T)
于 2016-09-27T19:15:56.833 に答える