включая параметры в OPENQUERY - PullRequest
75 голосов
/ 31 июля 2010

Как я могу использовать параметр внутри 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

Ответы [ 11 ]

134 голосов
/ 31 июля 2010

В документации OPENQUERY указано, что:

OPENQUERY не принимает переменные за свои аргументы.

См. Эту статью для обходного пути.

UPDATE:

Как и предполагалось, я включаю рекомендации из статьи ниже.

Передать базовые значения

Если базовый оператор Transact-SQL известен, но вам нужно передать одно или несколько конкретных значений, используйте код, подобный следующему примеру:

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
14 голосов
/ 31 июля 2010

Вы можете выполнить строку с 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)
11 голосов
/ 31 июля 2010

Со страницы 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 содержит большой объем данных, это также будет распространяться по всей сети и производительность может быть низкой.С другой стороны, для небольшого объема данных это работает хорошо и позволяет избежать динамических накладных расходов на создание sql (внедрение sql, экранирование кавычек), которые могут потребоваться для подхода exec.

6 голосов
/ 13 июня 2014

На самом деле, мы нашли способ сделать это:

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.

Мы тестировали процедуру Store в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)

4 голосов
/ 04 мая 2012
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.
2 голосов
/ 07 ноября 2014
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
1 голос
/ 08 апреля 2014

В следующем примере я передаю параметр отдела в хранимую процедуру (spIncreaseTotalsRpt) и одновременно создаю временную таблицу из OPENQUERY. Таблица Temp должна быть глобальной Temp (##), чтобы на нее можно было ссылаться за пределами ее intance. Используя 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

Результаты

Увеличение Dept Cnt 0 1 2 3 4 5 6 0,0000 1,0000 0,0000 0,0000 0,0000 0,0000 0,0000 0,0000

0 голосов
/ 22 мая 2017

Объединение динамического 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;
0 голосов
/ 27 сентября 2016

Простой пример, основанный на приведенном выше примере @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)
0 голосов
/ 19 августа 2015
declare @p_Id varchar(10)
SET @p_Id = '40381'

EXECUTE ('BEGIN update TableName
                set     ColumnName1 = null,
                        ColumnName2 = null,
                        ColumnName3 = null,
                        ColumnName4 = null
                 where   PERSONID = '+ @p_Id +'; END;') AT [linked_Server_Name]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...