Làm cách nào để sử dụng một tham số bên trong sql openquery, chẳng hạn như:
SELECT * FROM OPENQUERY([NameOfLinkedSERVER], 'SELECT * FROM TABLENAME
where field1=@someParameter') T1 INNER JOIN MYSQLSERVER.DATABASE.DBO.TABLENAME
T2 ON T1.PK = T2.PK
Làm cách nào để sử dụng một tham số bên trong sql openquery, chẳng hạn như:
SELECT * FROM OPENQUERY([NameOfLinkedSERVER], 'SELECT * FROM TABLENAME
where field1=@someParameter') T1 INNER JOIN MYSQLSERVER.DATABASE.DBO.TABLENAME
T2 ON T1.PK = T2.PK
Câu trả lời:
Từ tài liệu OPENQUERY, nó nói rằng:
OPENQUERY không chấp nhận các biến cho các đối số của nó.
Xem bài viết này để biết cách giải quyết.
CẬP NHẬT:
Như được đề xuất, tôi bao gồm các đề xuất từ bài viết bên dưới.
Vượt qua các giá trị cơ bản
Khi đã biết câu lệnh Transact-SQL cơ bản, nhưng bạn phải chuyển một hoặc nhiều giá trị cụ thể, hãy sử dụng mã tương tự như mẫu sau:
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)
Vượt qua toàn bộ truy vấn
Khi bạn phải chuyển toàn bộ truy vấn Transact-SQL hoặc tên của máy chủ được liên kết (hoặc cả hai), hãy sử dụng mã tương tự như mẫu sau:
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)
Sử dụng thủ tục lưu trữ Sp_executesql
Để tránh các dấu ngoặc kép nhiều lớp, hãy sử dụng mã tương tự như mẫu sau:
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
INSERT INTO @TableVariable EXEC sp_executeSql @TSQL
SELECT * FROM tab WHERE col = 'Y'
. Để vượt qua rằng tuyên bố như là một chuỗi để OpenQuery, tất cả các dấu nháy đơn cần thoát: SELECT * FROM OPENQUERY(Server, 'SELECT * FROM tab WHERE col = ''Y'' ')
. Sau đó, để vượt qua SELECT sử dụng OpenQuery Dynamic SQL, CÁC VẤN ĐỀ dấu ngoặc kép phải được thoát ra: EXEC sp_executeSQL 'SELECT * FROM OPENQUERY(Server, ''SELECT * FROM tab WHERE col = ''''Y'''' '')'
. Hi vọng điêu nay co ich!
SET @DAX = REPLACE(@DAX, '''', '''''')
Bạn có thể thực thi một chuỗi với OPENQUERY sau khi bạn xây dựng nó. Nếu bạn đi theo con đường này, hãy nghĩ về bảo mật và cẩn thận không nối văn bản do người dùng nhập vào SQL của bạn!
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)
if
, ví dụ như trongif (SELECT Col1 FROM OPENQUERY('Select ...') > 0 ) BEGIN ... END
Từ trang MSDN :
OPENQUERY không chấp nhận các biến cho các đối số của nó
Về cơ bản, điều này có nghĩa là bạn không thể đưa ra một truy vấn động. Để đạt được những gì mẫu của bạn đang cố gắng, hãy thử cách này:
SELECT * FROM
OPENQUERY([NameOfLinkedSERVER], 'SELECT * FROM TABLENAME') T1
INNER JOIN
MYSQLSERVER.DATABASE.DBO.TABLENAME T2 ON T1.PK = T2.PK
where
T1.field1 = @someParameter
Rõ ràng nếu bảng TABLENAME của bạn chứa một lượng lớn dữ liệu, thì dữ liệu này cũng sẽ đi qua mạng và hiệu suất có thể kém. Mặt khác, đối với một lượng nhỏ dữ liệu, điều này hoạt động tốt và tránh các chi phí xây dựng sql động (chèn sql, dấu ngoặc kép) mà một exec
phương pháp có thể yêu cầu.
Trên thực tế, chúng tôi đã tìm ra cách để làm điều này:
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
Điều này sẽ chỉ định kết quả của việc thực thi OpenQuery, trong biến @Output.
Chúng tôi đã thử nghiệm thủ tục Store trong MSSQL 2012, nhưng sẽ hoạt động với MSSQL 2008+.
Microsoft nói rằng sp_executesql (Transact-SQL): Áp dụng cho: SQL Server (SQL Server 2008 đến phiên bản hiện tại), Cơ sở dữ liệu Windows Azure SQL (Bản phát hành ban đầu cho đến bản phát hành hiện tại). ( 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.
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
Kết hợp SQL động với OpenQuery. (Điều này đến máy chủ 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;
Trong ví dụ sau, tôi đang chuyển một tham số của bộ phận tới một thủ tục được lưu trữ (spIncreaseTotalsRpt) và đồng thời tôi đang tạo một bảng tạm thời từ một OPENQUERY. Bảng Temp cần phải là một Temp toàn cục (##) để nó có thể được tham chiếu bên ngoài nội dung của nó. Bằng cách sử dụng execute sp_executesql, bạn có thể chuyển tham số bộ phận.
Lưu ý: hãy cẩn thận khi sử dụng sp_executeSQL. Ngoài ra, quản trị viên của bạn có thể không có tùy chọn này cho bạn.
Hy vọng điều này sẽ giúp ai đó.
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
Các kết quả
Tăng tiền gửi Cnt 0 1 2 3 4 5 6 0,0000 1,0000 0,0000 0,0000 0,0000 0,0000 0,0000 0,0000
Tôi đã tìm ra một cách phù hợp với tôi. Nó yêu cầu sử dụng một bảng cào mà một máy chủ được liên kết có quyền truy cập.
Tôi đã tạo một bảng và điền nó với các giá trị tôi cần, sau đó tôi tham chiếu bảng đó thông qua một máy chủ được liên kết.
SELECT *
FROM OPENQUERY(KHSSQLODSPRD,'SELECT *
FROM ABC.dbo.CLAIM A WITH (NOLOCK)
WHERE A.DOS >= (SELECT MAX(DATE) FROM KHSDASQL01.DA_MAIN.[dbo].[ALLFILENAMES]) ')
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]
openquery
cũng nên biết cách làm này. Nó cũng sạch hơn nhiều. Vì vậy, +1 từ phía tôi.
Chúng ta có thể sử dụng execute
phương pháp thay vì openquery
. Mã của nó sạch hơn nhiều. Tôi phải nhận linked server
kết quả truy vấn trong một biến. Tôi đã sử dụng mã sau đây.
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
Ghi chú:
nếu truy vấn của bạn không hoạt động, hãy đảm bảo rằng bạn
remote proc transaction promotion
được đặt nhưfalse
cholinked server
kết nối của mình .
EXEC master.dbo.sp_serveroption
@server = N'{linked server name}',
@optname = N'remote proc transaction promotion',
@optvalue = N'false';
Ví dụ đơn giản dựa trên ví dụ của @Tuan Zaidi ở trên, có vẻ dễ nhất. Không biết rằng bạn có thể thực hiện bộ lọc bên ngoài OPENQUERY ... dễ dàng hơn nhiều!
Tuy nhiên, trong trường hợp của tôi, tôi cần phải đưa nó vào một biến, vì vậy tôi đã tạo thêm Cấp truy vấn phụ để trả về một giá trị duy nhất.
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)