OPENQUERY'deki parametreler dahil


86

Sql openquery içinde bir parametreyi nasıl kullanabilirim, örneğin:

SELECT * FROM OPENQUERY([NameOfLinkedSERVER], 'SELECT * FROM TABLENAME
where field1=@someParameter') T1 INNER JOIN MYSQLSERVER.DATABASE.DBO.TABLENAME
T2 ON T1.PK = T2.PK

Geçici bir çözüm, açık sorgu ile bir görünüm oluşturmak ve ardından birleşimdeki görünümü kullanmaktır
Ismael

Yanıtlar:


156

Gönderen OPENQUERY belgeleri o belirtmektedir:

OPENQUERY, bağımsız değişkenleri için değişkenleri kabul etmez.

Çözüm için bu makaleye bakın .

GÜNCELLEME:

Önerildiği gibi, aşağıdaki makaledeki önerileri ekliyorum.

Temel Değerleri Geç

Temel Transact-SQL ifadesi bilindiğinde, ancak bir veya daha fazla belirli değeri iletmeniz gerektiğinde, aşağıdaki örneğe benzer bir kod kullanın:

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)

Tüm Sorguyu Geç

Transact-SQL sorgusunun tamamını veya bağlantılı sunucunun adını (veya her ikisini) iletmeniz gerektiğinde, aşağıdaki örneğe benzer bir kod kullanın:

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 Depolanan Prosedürünü kullanın

Çok katmanlı alıntılardan kaçınmak için aşağıdaki örneğe benzer bir kod kullanın:

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
Bu örneklerden herhangi birini kullanarak exec komutundan döndürülen kayıtları nasıl alırsınız?
philreed

2
Kayıtları almak için, her zaman sonuç kümemin bir tablo değişkeni veya geçici tablosunu oluşturdum, sonra kullandımINSERT INTO @TableVariable EXEC sp_executeSql @TSQL
Bret

6
@JamesChen, geriye doğru ne zaman çalıştığını düşünmek en kolay yoldur. OPENQUERY sorgusuna başlayın: SELECT * FROM tab WHERE col = 'Y'. OpenQuery bir dize olarak bu ifadeyi geçirmek için tüm tek tırnak kaçmış gerek: SELECT * FROM OPENQUERY(Server, 'SELECT * FROM tab WHERE col = ''Y'' '). Sonra, Dinamik SQL SorguAç kullanarak SEÇ geçmek, BU tırnak öncelenmelidirler: EXEC sp_executeSQL 'SELECT * FROM OPENQUERY(Server, ''SELECT * FROM tab WHERE col = ''''Y'''' '')'. Bu yardımcı olur umarım!
Bret

(yorumlarda @ kullanılamaz, dolayısıyla 'at' kullanılır) Parametreli Dinamik DAX ... DAX dizesini hazırladım ama Openquery çalışmadı. Tüm Sorguyu Geç yöntemi çalıştı. DAX'ımı bununla çalıştırdım: SET atDAX = REPLACE (atDAX, '' '', '' '' '') ve sonunda dizeyi kapatmam ve son bir parantez eklemem gerekiyor ... EXEC (atOPENQUERY + atDAX + '' '' + ')')
TDP

@TDP, satır içi kodu satır içi kod olarak biçimlendirdiyseniz (backticks kullanarak):SET @DAX = REPLACE(@DAX, '''', '''''')
Mathieu Guindon

15

Bir dizeyi oluşturduktan sonra OPENQUERY ile çalıştırabilirsiniz. Bu rotaya giderseniz güvenliği düşünün ve kullanıcı tarafından girilen metni SQL'inize eklememeye dikkat edin!

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)

Maalesef, OpenQuery'yi bağlamında kullanmak istiyorsanız if, örneğinif (SELECT Col1 FROM OPENQUERY('Select ...') > 0 ) BEGIN ... END
Stefan Brendle

@Stefan - openquery'den seçim yapabilir ve sonuçları geçici bir tabloya ekleyebilirsiniz. Elbette, oradan seçenekleriniz çok fazla açılır.
Jagd

13

Gönderen MSDN sayfa :

OPENQUERY, bağımsız değişkenleri için değişkenleri kabul etmiyor

Temelde bu, dinamik bir sorgu yapamayacağınız anlamına gelir. Örneğinizin yapmaya çalıştığını elde etmek için şunu deneyin:

SELECT * FROM 
   OPENQUERY([NameOfLinkedSERVER], 'SELECT * FROM TABLENAME') T1 
   INNER JOIN 
   MYSQLSERVER.DATABASE.DBO.TABLENAME T2 ON T1.PK = T2.PK 
where
   T1.field1 = @someParameter

Açıkça görülüyor ki TABLENAME tablonuz büyük miktarda veri içeriyorsa, bu da ağa yayılacaktır ve performans düşük olabilir. Öte yandan, az miktarda veri için bu iyi çalışır ve bir execyaklaşımın gerektirebileceği dinamik sql inşaat genel giderlerinden (sql injection, kaçan alıntılar) kaçınır .


bu, başarmaya çalıştığım şeyi başarmak için doğru yola işaret etti! Teşekkür ederim! bu daha fazla olumlu oy almalı
Malachi

7

Aslında bunu yapmanın bir yolunu bulduk:

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

Bu, OpenQuery yürütmesinin sonucunu @Output değişkenine atayacaktır.

Mağaza prosedürünü MSSQL 2012'de test ettik, ancak MSSQL 2008+ ile çalışmalıdır.

Microsoft, sp_executesql (Transact-SQL): Şunlar için geçerlidir: SQL Server (SQL Server 2008'den geçerli sürümden), Windows Azure SQL Veritabanı (Geçerli sürümden ilk sürüm). ( http://msdn.microsoft.com/en-us/library/ms188001.aspx )


Bu yalnızca Skaler çıktı için çalışır. Xml veya bir Tablo değişkenini deneyin ve bu işe yaramayacak.
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
Bu kodun , TABLENAME'in TÜM satırları için A) alan1'in bağlı sunucudan geçirileceği konusunda bir uyarıya ihtiyacı vardır - bu potansiyel olarak çok pahalı bir işlemdir. B) INNER JOIN aynı zamanda 'çok pahalı' olabilir
brewmanz

2

Dinamik SQL'i OpenQuery ile birleştirin. (Bu bir Teradata sunucusuna gider)

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

Aşağıdaki örnekte bir departman parametresini bir saklı yordama (spIncreaseTotalsRpt) geçiriyorum ve aynı zamanda bir OPENQUERY'den geçici bir tablo oluşturuyorum. Temp tablosunun genel bir Temp (##) olması gerekir, böylece girişinin dışında referans alınabilir. Exec sp_executesql kullanarak departman parametresini geçebilirsiniz.

Not: sp_executeSQL kullanırken dikkatli olun. Ayrıca yöneticiniz bu seçeneği kullanamayabilir.

Umarım bu birine yardımcı olur.

 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

Sonuçlar

Derinlik artışı Cnt 0 1 2 3 4 5 6 0.0000 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000


0

Benim için işe yarayan bir yol buldum. Bağlantılı bir sunucunun erişime sahip olduğu bir çalışma tablosunun kullanılmasını gerektirir .

Bir tablo oluşturdum ve onu ihtiyacım olan değerlerle doldurdum, sonra bu tabloya bağlı bir sunucu üzerinden başvurdum.

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]

Anahtar kelime openquery dude :)
Christian

alternatif bir yaklaşımdır. Kim bilirse openquerybu yaklaşımı da bilmelidir. Aynı zamanda çok daha temiz. Yani +1 benden.
Şeyh Abdul Wahid

0

executeBunun yerine yöntemi kullanabiliriz openquery. Kodu çok daha temiz. linked serverBir değişkende sorgu sonucunu almam gerekiyordu . Aşağıdaki kodu kullandım.

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

Not:

Sorgunuz işe yaramazsa, lütfen bağlantınız için remote proc transaction promotionayarlandığından emin olun .falselinked server

EXEC master.dbo.sp_serveroption
       @server = N'{linked server name}',
       @optname = N'remote proc transaction promotion',
       @optvalue = N'false';

-1

En kolay görünen @Tuan Zaidi'nin yukarıdaki örneğine dayanan basit bir örnek. OPENQUERY dışında filtre uygulayabileceğinizi bilmiyordum ... çok daha kolay!

Ancak benim durumumda onu bir değişkene doldurmam gerekiyordu, bu yüzden tek bir değer döndürmek için ek bir Alt Sorgu Düzeyi oluşturdum.

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

Sadece bu şekilde dene, çalışmalı, kolay! WHERE yan tümcenizde, sütun adından sonra ve işarete eşittir: - İKİ tek tırnak, arama değerinizi ve ardından ÜÇ tek tırnak ekleyin. Desteği kapatın.

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


Cevabınız sabit SQL kullanıyor, ancak OP bir parametre kullanmak istiyor (referansını not edin field1=@someParameter).
Jeff Mergler
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.