SQL 在 OPENQUERY 中包含参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3378496/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
including parameters in OPENQUERY
提问by gaponte69
How can I use a parameter inside sql openquery, such as:
如何在 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
回答by Garett
From the OPENQUERYdocumentation it states that:
从OPENQUERY文档中它指出:
OPENQUERY does not accept variables for its arguments.
OPENQUERY 不接受其参数的变量。
See this articlefor a workaround.
有关解决方法,请参阅此文章。
UPDATE:
更新:
As suggested, I'm including the recommendations from the article below.
按照建议,我将包括以下文章中的建议。
Pass Basic Values
传递基本值
When the basic Transact-SQL statement is known, but you have to pass in one or more specific values, use code that is similar to the following sample:
当基本 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)
Pass the Whole Query
传递整个查询
When you have to pass in the whole Transact-SQL query or the name of the linked server (or both), use code that is similar to the following sample:
当您必须传入整个 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)
Use the Sp_executesql Stored Procedure
使用 Sp_executesql 存储过程
To avoid the multi-layered quotes, use code that is similar to the following sample:
为避免多层引号,请使用类似于以下示例的代码:
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
回答by Tahbaza
You can execute a string with OPENQUERY once you build it up. If you go this route think about security and take care not to concatenate user-entered text into your SQL!
一旦你建立了它,你就可以用 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)
回答by Neil Moss
From the MSDN page:
从MSDN 页面:
OPENQUERY does not accept variables for its arguments
OPENQUERY 不接受其参数的变量
Fundamentally, this means you cannot issue a dynamic query. To achieve what your sample is attempting, try this:
从根本上说,这意味着您不能发出动态查询。要实现您的示例正在尝试的内容,请尝试以下操作:
SELECT * FROM
OPENQUERY([NameOfLinkedSERVER], 'SELECT * FROM TABLENAME') T1
INNER JOIN
MYSQLSERVER.DATABASE.DBO.TABLENAME T2 ON T1.PK = T2.PK
where
T1.field1 = @someParameter
Clearly if your TABLENAME table contains a large amount of data, this will go across the network too and performance might be poor. On the other hand, for a small amount of data, this works well and avoids the dynamic sql construction overheads (sql injection, escaping quotes) that an exec
approach might require.
很明显,如果您的 TABLENAME 表包含大量数据,这也会通过网络传输,性能可能会很差。另一方面,对于少量数据,这很有效,并且避免了exec
方法可能需要的动态 sql 构建开销(sql 注入、转义引号)。
回答by Juan Medina
Actually, We found a way to do this:
实际上,我们找到了一种方法来做到这一点:
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
This will assign the result of the OpenQuery execution, in the variable @Output.
这将在变量@Output 中分配 OpenQuery 执行的结果。
We tested for Store procedure in MSSQL 2012, but should work with MSSQL 2008+.
我们在 MSSQL 2012 中测试了存储过程,但应该可以与 MSSQL 2008+ 一起使用。
Microsoft Says that sp_executesql(Transact-SQL): Applies to: SQL Server (SQL Server 2008 through current version), Windows Azure SQL Database (Initial release through current release). (http://msdn.microsoft.com/en-us/library/ms188001.aspx)
Microsoft 表示 sp_executesql(Transact-SQL):适用于:SQL Server(SQL Server 2008 到当前版本)、Windows Azure SQL 数据库(初始版本到当前版本)。( http://msdn.microsoft.com/en-us/library/ms188001.aspx)
回答by Ryan Maloney
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.
回答by Tuan Zaidi
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
回答by Mike
Combine Dynamic SQL with OpenQuery. (This goes to a Teradata server)
将动态 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;
回答by Carlos
In the following example I'm passing a department parameter to a stored procedure(spIncreaseTotalsRpt) and at the same time I'm creating a temp table all from an OPENQUERY. The Temp table needs to be a global Temp (##) so it can be referenced outside it's intance. By using exec sp_executesql you can pass the department parameter.
在下面的示例中,我将一个部门参数传递给一个存储过程 (spIncreaseTotalsRpt),同时我正在从 OPENQUERY 创建一个临时表。Temp 表需要是一个全局 Temp (##),所以它可以在它的实例之外被引用。通过使用 exec sp_executesql 您可以传递部门参数。
Note: be careful when using sp_executeSQL. Also your admin might not have this option available to you.
注意:使用 sp_executeSQL 时要小心。此外,您的管理员可能没有此选项可供您使用。
Hope this helps someone.
希望这可以帮助某人。
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
Results
结果
Dept increase Cnt 0 1 2 3 4 5 6 0.0000 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
部门增加 Cnt 0 1 2 3 4 5 6 0.0000 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
回答by Hannover Fist
I figured out a way that works for me. It does require the use of a scratch table that a linked serverhas access to though.
我想出了一个对我有用的方法。它确实需要使用链接服务器可以访问的临时表。
I created a table and populated it with the values I need then I reference that table through a linked server.
我创建了一个表并用我需要的值填充它,然后我通过链接服务器引用该表。
SELECT *
FROM OPENQUERY(KHSSQLODSPRD,'SELECT *
FROM ABC.dbo.CLAIM A WITH (NOLOCK)
WHERE A.DOS >= (SELECT MAX(DATE) FROM KHSDASQL01.DA_MAIN.[dbo].[ALLFILENAMES]) ')
回答by Sheikh Abdul Wahid
We can use execute
method instead of openquery
. Its code is much cleaner. I had to get linked server
query result in a variable. I used following code.
我们可以使用execute
method 代替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
Note:
笔记:
if your query doesn't work, please make sure
remote proc transaction promotion
is set asfalse
for yourlinked server
connection.
如果您的查询不起作用,请确保为您的连接
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';