termasuk parameter di OPENQUERY


86

Bagaimana saya bisa menggunakan parameter di dalam sql openquery, seperti:

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

Solusinya adalah membuat tampilan dengan openquery dan kemudian menggunakan tampilan di join
Ismael

Jawaban:


156

Dari dokumentasi OPENQUERY disebutkan bahwa:

OPENQUERY tidak menerima variabel untuk argumennya.

Lihat artikel ini untuk solusinya.

MEMPERBARUI:

Seperti yang disarankan, saya menyertakan rekomendasi dari artikel di bawah ini.

Lulus Nilai Dasar

Ketika pernyataan Transact-SQL dasar diketahui, tetapi Anda harus meneruskan satu atau lebih nilai tertentu, gunakan kode yang mirip dengan contoh berikut:

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)

Lulus Kueri Utuh

Saat Anda harus meneruskan seluruh kueri Transact-SQL atau nama server tertaut (atau keduanya), gunakan kode yang mirip dengan contoh berikut:

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) 

Gunakan Prosedur Tersimpan Sp_executesql

Untuk menghindari kutipan berlapis-lapis, gunakan kode yang mirip dengan contoh berikut:

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
Dengan menggunakan salah satu contoh berikut, bagaimana Anda mengambil catatan yang dikembalikan dari perintah exec?
Philreed

2
Untuk mengambil catatan, saya selalu membuat variabel tabel atau tabel temp dari kumpulan hasil saya, lalu menggunakanINSERT INTO @TableVariable EXEC sp_executeSql @TSQL
Bret

6
@JamesChen, paling mudah untuk dipikirkan saat Anda bekerja mundur. Mulailah dengan query OpenQuery ini: SELECT * FROM tab WHERE col = 'Y'. Untuk lulus bahwa pernyataan sebagai string untuk OpenQuery, semua tanda kutip tunggal perlu melarikan diri: SELECT * FROM OPENQUERY(Server, 'SELECT * FROM tab WHERE col = ''Y'' '). Kemudian, untuk lulus SELECT menggunakan OpenQuery ke Dynamic SQL, MEREKA kutipan harus melarikan diri: EXEC sp_executeSQL 'SELECT * FROM OPENQUERY(Server, ''SELECT * FROM tab WHERE col = ''''Y'''' '')'. Semoga ini membantu!
Bret

(tidak dapat menggunakan @ di komentar jadi menggunakan 'at') DAX dinamis dengan params ... Saya menyiapkan string DAX tetapi Openquery tidak berfungsi. Meneruskan metode Kueri Utuh berhasil. Jalankan DAX saya melalui ini: SET atDAX = REPLACE (atDAX, '' '', '' '' '') dan pada akhirnya saya harus menutup string dan menambahkan braket terakhir ... EXEC (atOPENQUERY + atDAX + '' '' + ')')
TDP

@TDP Anda bisa, jika Anda memformat kode inline sebagai kode inline (menggunakan backticks):SET @DAX = REPLACE(@DAX, '''', '''''')
Mathieu Guindon

15

Anda dapat mengeksekusi string dengan OPENQUERY setelah Anda membuatnya. Jika Anda mengikuti rute ini, pikirkan tentang keamanan dan berhati-hatilah untuk tidak menggabungkan teks yang dimasukkan pengguna ke dalam SQL Anda!

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)

Sayangnya itu tidak berhasil, jika Anda ingin menggunakan OpenQuery dalam konteks dengan if, misalnya diif (SELECT Col1 FROM OPENQUERY('Select ...') > 0 ) BEGIN ... END
Stefan Brendle

@ Stefan - Anda dapat memilih dari openquery dan memasukkan hasilnya ke dalam tabel sementara. Dari sana pilihan Anda banyak terbuka, tentu saja.
Jagd

13

Dari halaman MSDN :

OPENQUERY tidak menerima variabel untuk argumennya

Pada dasarnya, ini berarti Anda tidak dapat mengeluarkan kueri dinamis. Untuk mencapai apa yang sampel Anda coba, coba ini:

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

Jelas jika tabel TABLENAME Anda berisi data dalam jumlah besar, ini juga akan melewati jaringan dan kinerjanya mungkin buruk. Di sisi lain, untuk sejumlah kecil data, ini berfungsi dengan baik dan menghindari overhead konstruksi sql dinamis (injeksi sql, tanda kutip pelolosan) yang execmungkin diperlukan oleh suatu pendekatan.


ini mengarahkan saya ke jalan yang benar untuk berhasil dalam apa yang saya coba capai! Terima kasih! ini seharusnya memiliki lebih banyak suara positif
Malachi

7

Sebenarnya, Kami menemukan cara untuk melakukan ini:

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

Ini akan menetapkan hasil eksekusi OpenQuery, dalam variabel @Output.

Kami menguji prosedur Store di MSSQL 2012, tetapi seharusnya berfungsi dengan MSSQL 2008+.

Microsoft Mengatakan bahwa sp_executesql (Transact-SQL): Berlaku untuk: SQL Server (SQL Server 2008 melalui versi saat ini), Database Windows Azure SQL (Rilis awal melalui rilis saat ini). ( http://msdn.microsoft.com/en-us/library/ms188001.aspx )


Ini hanya berfungsi untuk keluaran Skalar. Coba Xml atau variabel Tabel dan ini tidak akan berhasil.
pengguna5855178

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
Kode ini memerlukan peringatan bahwa A) bidang1 untuk SEMUA baris TABLENAME akan diteruskan dari server tertaut - operasi yang berpotensi sangat mahal. B) INNER JOIN juga bisa 'sangat mahal'
brewmanz

2

Gabungkan SQL Dinamis dengan OpenQuery. (Ini masuk ke server 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

Dalam contoh berikut, saya meneruskan parameter departemen ke prosedur tersimpan (spIncreaseTotalsRpt) dan pada saat yang sama saya membuat tabel temp semua dari OPENQUERY. Tabel Temp harus menjadi Temp global (##) sehingga dapat direferensikan di luar maksudnya. Dengan menggunakan exec sp_executesql Anda bisa melewatkan parameter departemen.

Catatan: hati-hati saat menggunakan sp_executeSQL. Juga admin Anda mungkin tidak memiliki opsi ini tersedia untuk Anda.

Semoga ini bisa membantu seseorang.

 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

Hasil

Peningkatan dept 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

Saya menemukan cara yang berhasil untuk saya. Itu memang membutuhkan penggunaan tabel awal yang memiliki akses ke server tertaut .

Saya membuat tabel dan mengisinya dengan nilai yang saya butuhkan kemudian saya mereferensikan tabel itu melalui server tertaut.

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]

Kata kuncinya adalah openquery dude :)
Christian

itu adalah pendekatan alternatif. Siapa pun yang tahu openqueryharus mengetahui pendekatan ini juga. Ini juga jauh lebih bersih. Jadi +1 dari sisi saya.
Sheikh Abdul Wahid

0

Kita bisa menggunakan executemetode daripada openquery. Kodenya jauh lebih bersih. Saya harus mendapatkan linked serverhasil kueri dalam variabel. Saya menggunakan kode berikut.

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

catatan:

jika kueri Anda tidak berhasil, pastikan remote proc transaction promotiondisetel sebagai koneksi falseAnda linked server.

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

-1

Contoh sederhana berdasarkan contoh @Tuan Zaidi di atas yang sepertinya paling mudah. Tidak tahu Anda bisa melakukan filter di luar OPENQUERY ... jadi lebih mudah!

Namun dalam kasus saya, saya perlu memasukkannya ke dalam variabel jadi saya membuat Sub Query Level tambahan untuk mengembalikan satu nilai.

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

Coba saja cara ini, semestinya berhasil, mudah! Di klausa WHERE Anda, setelah nama kolom dan tanda sama dengan: - tambahkan DUA tanda kutip tunggal, nilai pencarian Anda, lalu TIGA tanda kutip tunggal. Tutup braket.

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


Jawaban Anda menggunakan SQL literal, tetapi OP ingin menggunakan parameter (perhatikan referensinya field1=@someParameter).
Jeff Mergler
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.