OPENQUERY에 매개 변수 포함


86

다음과 같은 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

해결 방법은 openquery로 뷰를 생성 한 다음 조인에서 뷰를 사용하는 것입니다
Ismael

답변:


156

로부터 OPENQUERY의 문서는 그 상태 :

OPENQUERY는 인수에 대한 변수를 허용하지 않습니다.

해결 방법 은이 문서 를 참조하십시오 .

최신 정보:

제안 된대로 아래 기사의 권장 사항을 포함합니다.

기본 값 통과

기본 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

9
이러한 예를 사용하여 exec 명령에서 반환 된 레코드를 어떻게 검색합니까?
philreed

2
레코드를 검색하기 위해 항상 내 결과 집합의 테이블 변수 또는 임시 테이블을 만든 다음INSERT INTO @TableVariable EXEC sp_executeSql @TSQL
Bret

6
@JamesChen, 거꾸로 작업 할 때 생각하는 것이 가장 쉽습니다. OpenQuery의 쿼리로 시작 SELECT * FROM tab WHERE col = 'Y'합니다.. 해당 문을 OpenQuery에 문자열로 전달하려면 모든 작은 따옴표를 이스케이프해야 SELECT * FROM OPENQUERY(Server, 'SELECT * FROM tab WHERE col = ''Y'' ')합니다.. 그런 다음 OpenQuery를 사용하여 SELECT를 동적 SQL에 전달하려면 THOSE 따옴표를 이스케이프해야합니다 EXEC sp_executeSQL 'SELECT * FROM OPENQUERY(Server, ''SELECT * FROM tab WHERE col = ''''Y'''' '')'.. 도움이 되었기를 바랍니다!
Bret

(주석에 @를 사용할 수 없으므로 'at'을 사용) 동적 DAX with params ... DAX 문자열을 준비했지만 Openquery가 작동하지 않았습니다. 전체 쿼리 방법을 전달하십시오. 이것을 통해 내 DAX를 실행했습니다 : SET atDAX = REPLACE (atDAX, '' '', '' '' '') 마지막에 문자열을 닫고 마지막 대괄호를 추가해야했습니다 ... EXEC (atOPENQUERY + atDAX + '' ''+ ')')
TDP

인라인 코드와 인라인 코드를 포맷하는 경우 @TDP 당신이 수 (역 따옴표를 사용)SET @DAX = REPLACE(@DAX, '''', '''''')
마티유 Guindon

15

일단 빌드하면 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)

안타깝게도 작동하지 않습니다. if예를 if (SELECT Col1 FROM OPENQUERY('Select ...') > 0 ) BEGIN ... END
들어와

@Stefan-openquery에서 선택하고 결과를 임시 테이블에 삽입 할 수 있습니다. 물론 거기에서 옵션이 많이 열립니다.
Jagd

13

로부터 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 테이블에 많은 양의 데이터가 포함 된 경우 분명히 네트워크를 통해 전송되며 성능이 저하 될 수 있습니다. 반면에 소량의 데이터의 경우 이는 잘 작동하며 exec접근 방식에 필요할 수있는 동적 SQL 생성 오버 헤드 (SQL 주입, 이스케이프 따옴표)를 방지 합니다.


이것은 내가 이루고자하는 일에서 성공할 수있는 올바른 길을 알려 줬습니다! 감사합니다! 이것은 더 많은
Malachi

7

실제로이 작업을 수행하는 방법을 찾았습니다.

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에서 저장 프로 시저를 테스트했지만 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 )


이것은 Scalar 출력에서만 작동합니다. Xml 또는 Table 변수를 시도하면 작동하지 않습니다.
user5855178

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.

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

4
이 코드에는 A) TABLENAME의 모든 행에 대한 field1 이 연결된 서버에서 전달 될 것이라는 경고가 필요합니다. 이는 잠재적으로 매우 비용이 많이 드는 작업입니다. B) INNER JOIN도 '매우 비쌀'수 있습니다.
brewmanz

2

동적 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;

1

다음 예에서는 부서 매개 변수를 저장 프로 시저 (spIncreaseTotalsRpt)에 전달하고 동시에 OPENQUERY에서 임시 테이블을 만듭니다. Temp 테이블은 인텐스 외부에서 참조 할 수 있도록 전역 Temp (##) 여야합니다. 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

결과

부서 증가 Cnt 012 34 5 6 0.0000 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000


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

0
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의 친구입니다
기독교

대체 접근 방식입니다. 아는 사람은 openquery이 접근 방식도 알아야합니다. 또한 훨씬 더 깨끗합니다. 그래서 내 쪽에서 +1.
Sheikh Abdul Wahid

0

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

노트 :

귀하의 요청이없는 작업을 수행하는 경우, 확인하십시오 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';

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

-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


귀하의 답변은 리터럴 SQL을 사용하지만 OP는 매개 변수를 사용하려고합니다 (를 참조하십시오 field1=@someParameter).
Jeff Mergler
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.