如何在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
答案 0 :(得分:132)
从OPENQUERY文档中可以看出:
OPENQUERY不接受变量 因为它的论点。
有关解决方法,请参阅此article。
<强>更新强>
根据建议,我将包括以下文章中的建议。
传递基本值
当已知基本的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
答案 1 :(得分:14)
一旦构建完毕,就可以使用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)
答案 2 :(得分:11)
来自MSDN page:
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注入,转义引号)。
答案 3 :(得分:6)
实际上,我们找到了一种方法:
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
这将在变量@Output。
中分配OpenQuery执行的结果我们在MSSQL 2012中测试了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)
答案 4 :(得分: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.
答案 5 :(得分:2)
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
答案 6 :(得分:1)
在下面的示例中,我将一个department参数传递给存储过程(spIncreaseTotalsRpt),同时我从一个OPENQUERY创建一个临时表。 Temp表需要是一个全局Temp(##),因此它可以在它的intance之外引用。 通过使用exec sp_executesql,您可以传递department参数。
注意:使用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
答案 7 :(得分: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]) ')
答案 8 :(得分:0)
将动态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;
答案 9 :(得分:0)
我们可以使用execute
方法来代替openquery
。它的代码更简洁。我必须在一个变量中获取linked server
查询结果。我使用了以下代码。
CREATE TABLE #selected_store
(
code VARCHAR(250),
id INT
)
declare @storeId as integer = 25
insert into #selected_store (id, code) execute('SELECT store_id, code from quickstartproductionnew.store where store_id = ?', @storeId) at [MYSQL]
declare @code as varchar(100)
select @code = code from #selected_store
select @code
drop table #selected_store
注意:
如果您的查询无效,请确保将
remote proc transaction promotion
连接的false
设置为linked server
。
EXEC master.dbo.sp_serveroption
@server = N'{linked server name}',
@optname = N'remote proc transaction promotion',
@optvalue = N'false';
答案 10 :(得分:0)
DECLARE @usernames NVARCHAR(MAX);
SET @usernames = N'';
DECLARE @len INT;
SELECT @usernames = @usernames + ISNULL(username + ''''',''''', '')
FROM #tempusername;
SET @len = len(@usernames);
SET @usernames = N'''''' + LEFT(@usernames, @len - 3);
DECLARE @sql NVARCHAR(MAX);
SET @sql
= N'SELECT *
FROM OPENQUERY
([Linked Server],
''SELECT username
FROM [MySQL Database].[Table Name]
WHERE username IN ( ' + @usernames + N')'')';
我在此链接 https://social.technet.microsoft.com/Forums/en-US/98e0c17a-8ead-4633-a053-51c49b313bd3/how-can-i-use-a-table-variable-as-a-parameter-for-openquery?forum=sqltools&prof=required 上找到了此解决方法 很有帮助。
答案 11 :(得分:-1)
简单的例子基于@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)
答案 12 :(得分:-1)
只需尝试这种方式,就可以轻松完成!在您的WHERE子句中,在列名之后等于等号:-添加两个单引号,您的搜索值,然后添加三个单引号。合上支架。
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
答案 13 :(得分:-2)
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]