包括OPENQUERY中的参数

我如何使用SQL查询中的一个参数,如:

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不接受variables的参数。

请参阅这篇文章的解决方法。

更新:

正如所build议的,我将包括下面的文章的build议。

通过基本价值

当基本的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 

一旦你build立起来,你可以用OPENQUERY来执行一个string。 如果你走这条路线考虑安全性,并注意不要将用户input的文本连接到你的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不接受variables的参数

基本上,这意味着你不能发出dynamic查询。 要实现您的示例正在尝试,请尝试以下操作:

 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表包含大量的数据,这也将通过networking,性能可能会很差。 另一方面,对于less量的数据,这个效果很好,避免了exec方法可能需要的dynamicsql构造开销(sql注入,转义引用)。

其实,我们find了一个方法来做到这一点:

 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 

这将在variables@Output中分配OpenQuery执行的结果。

我们在MSSQL 2012中testing了Store程序,但是应该使用MSSQL 2008+。

Microsoft说sp_executesql(Transact-SQL):适用于:SQL Server(通过当前版本的SQL Server 2008),Windows Azure SQL数据库(通过当前版本的初始版本)。 ( 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. 

在下面的示例中,我将部门parameter passing给存储过程(spIncreaseTotalsRpt),同时我从OPENQUERY中创build临时表。 临时表需要是一个全局的Temp(##),所以它可以被引用到它的实例之外。 通过使用exec sp_executesql您可以传递部门参数。

注意:使用sp_executeSQL时要小心。 另外你的pipe理员可能没有这个选项可供你使用。

希望这有助于某人。

  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 field1 FROM OPENQUERY ([NameOfLinkedSERVER], 'SELECT field1 FROM TABLENAME') WHERE field1=@someParameter T1 INNER JOIN MYSQLSERVER.DATABASE.DBO.TABLENAME T2 ON T1.PK = T2.PK 

我想出了一个适合我的方法。 它确实需要使用链接服务器可以访问的临时表。

我创build了一个表,并使用我需要的值填充它,然后通过链接服务器引用该表。

 SELECT * FROM OPENQUERY(KHSSQLODSPRD,'SELECT * FROM ABC.dbo.CLAIM A WITH (NOLOCK) WHERE A.DOS >= (SELECT MAX(DATE) FROM KHSDASQL01.DA_MAIN.[dbo].[ALLFILENAMES]) ') 

将dynamicSQL与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; 

根据@Tuan Zaidi上面的例子,这个简单的例子似乎是最简单的。 不知道你可以做OPENQUERY的外面的filter…更容易!

但是在我的情况下,我需要将它填充到一个variables,所以我创build了一个额外的子查询级别返回一个单一的值。

 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) 
 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]