OPENQUERY में पैरामीटर शामिल हैं


86

मैं sql ओपनक्वेरी के अंदर एक पैरामीटर का उपयोग कैसे कर सकता हूं, जैसे:

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

एक वर्कअराउंड ओपनकीरी के साथ एक दृश्य बनाता है और फिर जुड़ने में दृश्य का उपयोग करते हुए
Ismael

जवाबों:


156

से OPENQUERY प्रलेखन यह है कि कहा गया है:

OPENQUERY अपने तर्कों के लिए चर को स्वीकार नहीं करता है।

इस लेख को वर्कअराउंड के लिए देखें ।

अपडेट करें:

जैसा कि सुझाव दिया गया है, मैं नीचे दिए गए लेख से सिफारिशों को शामिल कर रहा हूं।

बेसिक वैल्यूज पास करें

जब मूल लेनदेन-एसक्यूएल स्टेटमेंट ज्ञात होता है, लेकिन आपको एक या एक से अधिक विशिष्ट मानों को पास करना होता है, तो कोड का उपयोग करें जो निम्न नमूने के समान है:

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
इनमें से किसी भी उदाहरण का उपयोग करते हुए, आप निष्पादन कमांड से लौटे रिकॉर्ड को कैसे पुनः प्राप्त करते हैं?
दीक्षा

2
रिकॉर्ड पुनः प्राप्त करने के लिए, मैंने हमेशा अपने परिणाम सेट की एक तालिका चर या अस्थायी तालिका का निर्माण किया है, फिर इस्तेमाल कियाINSERT INTO @TableVariable EXEC sp_executeSql @TSQL
ब्रेट

6
@JamesChen, जब आप पीछे की ओर काम करते हैं, तो यह सोचना सबसे आसान है। OpenQuery की क्वेरी के साथ शुरू करें SELECT * FROM tab WHERE col = 'Y':। OpenQuery के लिए एक स्ट्रिंग के रूप में उस बयान को पारित करने के लिए, सभी एकल उद्धरणों से बचने की आवश्यकता है SELECT * FROM OPENQUERY(Server, 'SELECT * FROM tab WHERE col = ''Y'' '):। फिर, OpenSQL का उपयोग कर डायनेमिक SQL में पास करने के लिए, THOSE कोट्स से बच जाना चाहिए EXEC sp_executeSQL 'SELECT * FROM OPENQUERY(Server, ''SELECT * FROM tab WHERE col = ''''Y'''' '')':। उम्मीद है की यह मदद करेगा!
ब्रेट

(@ पर टिप्पणियों में @ का उपयोग नहीं कर सकते हैं) params के साथ गतिशील DAX ... मैं DAX स्ट्रिंग तैयार की, लेकिन Openquery काम नहीं किया। पूरी क्वेरी विधि पास काम किया। इसके माध्यम से मेरे DAX को रन करें: SET atDAX = REPLACE (एटडैक्स, '' '', '' '' '' ') और अंत में मुझे स्ट्रिंग को बंद करना होगा और एक अंतिम ब्रैकेट जोड़ना होगा ... EXEC (atOPQUQUERY + atDAX +) '' '' + ''))
टीडीपी

@ टीडीपी, यदि आप इनलाइन कोड को इनलाइन कोड (बैकटिक्स का उपयोग करके) के रूप में स्वरूपित कर सकते हैं:SET @DAX = REPLACE(@DAX, '''', '''''')
मैथ्यू गुइंडन

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उदाहरण के लिए OpenQuery का उपयोग करना चाहते हैं , उदाहरण के लिएif (SELECT Col1 FROM OPENQUERY('Select ...') > 0 ) BEGIN ... END
स्टीफन ब्रेंडल

@Stefan - आप ओपनक्वेरी से चयन कर सकते हैं और परिणाम एक अस्थायी तालिका में डाल सकते हैं। वहाँ से आपके विकल्प खुलते हैं, निश्चित रूप से।
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 तालिका में बड़ी मात्रा में डेटा है, तो यह नेटवर्क पर भी जाएगा और प्रदर्शन खराब हो सकता है। दूसरी ओर, डेटा की एक छोटी राशि के लिए, यह अच्छी तरह से काम करता है और गतिशील sql निर्माण ओवरहेड्स (sql इंजेक्शन, उद्धरण से बचने) से बचा जाता है जो एक execदृष्टिकोण की आवश्यकता हो सकती है।


इसने मुझे जो पूरा करने की कोशिश कर रहा था उसमें सफल होने का सही रास्ता बताया! धन्यवाद! यह अधिक होना चाहिए
मालाची

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 में प्रदान करेगा।

हमने MSSQL 2012 में स्टोर प्रक्रिया के लिए परीक्षण किया, लेकिन MSSQL 2008+ के साथ काम करना चाहिए।

Microsoft कहता है कि sp_executesql (Transact-SQL): इस पर लागू होता है: SQL सर्वर (SQL सर्वर 2008 वर्तमान संस्करण के माध्यम से), Windows Azure SQL डेटाबेस (वर्तमान रिलीज़ के माध्यम से प्रारंभिक रिलीज़)। ( http://msdn.microsoft.com/en-us/library/ms188001.aspx )


यह केवल स्केलर आउटपुट के लिए काम करता है। Xml या तालिका चर आज़माएँ और यह काम नहीं करने वाला है।
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
इस कोड को एक चेतावनी की आवश्यकता है कि TABLENAME की सभी पंक्तियों के लिए A) फ़ील्ड 1 को लिंक किए गए सर्वर से पार किया जाएगा - एक संभावित महंगा ऑपरेशन। B) INNER JOIN 'बहुत महंगा' भी हो सकता है
brewmanz

2

OpenQuery के साथ डायनामिक SQL को मिलाएं। (यह एक 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 (##) होने की आवश्यकता है, इसलिए इसे बाहर के उद्देश्य से संदर्भित किया जा सकता है। निष्पादित 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 0 1 2 3 4 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उसे इस दृष्टिकोण को जानना चाहिए। यह भी बहुत क्लीनर है। तो मेरी तरफ से +1।
शेख अब्दुल वाहिद

0

हम executeइसके बजाय विधि का उपयोग कर सकते हैं 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सेट किया गया है ।falselinked 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)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.