2012-02-10 17 views
9

का उपयोग कर SQL xml विशेषता मान प्राप्त करें मेरे पास एक SQL फ़ंक्शन है जो attribute नामक एक चर लेता है, जो xml विशेषता है जिसे मैं मान प्राप्त करना चाहता हूं। xmlPath पूर्ण एक्सएमएल स्ट्रिंग है।परिवर्तनीय

<EventSpecificData> 
    <Keyword> 
    <Word>myWord</Word> 
    <Occurences>1</Occurences> 
    <Context>context</Context> 
    </Keyword> 
</EventSpecificData> 

मैं <Word> के लिए मूल्य प्राप्त करना चाहते हैं, तो मैं /Keyword/Word में गुजरती हैं और एक चर करने के लिए सेट:

set @value = @xmlPath.value('(/EventSpecificData/@attribute)[1]', 'varchar(max)') 

हालांकि, मैं नहीं

मेरे एक्सएमएल इस तरह दिखता है लगता है कि @attribute वास्तव में चर स्ट्रिंग डालने है। क्या इसे करने का और कोई तरीका है?

+0

मुझे नहीं लगता कि आप ऐसा कर सकते हैं - SQL XQuery अक्सर शाब्दिक तारों के साथ काम करता है, और अधिकांश समय, उन्हें SQL चर के साथ प्रतिस्थापित नहीं किया जा सकता .... –

उत्तर

14

यहां आपके लिए कुछ समाधान दिए गए हैं।

नमूना डेटा:

declare @xml xml 
set @xml = 
'<EventSpecificData> 
    <Keyword> 
    <Word>myWord</Word> 
    <Occurences>1</Occurences> 
    <Context>context</Context> 
    </Keyword> 
</EventSpecificData>' 

माता-पिता की परवाह किए बिना पद नामित नोड से पहले मान प्राप्त करें। गहरी खोज करने के लिए // का उपयोग करें और नोड नाम से मेल खाने के लिए local-name() का उपयोग करें।

declare @Attribute varchar(max) 

set @Attribute = 'Word' 
select @xml.value('(//*[local-name() = sql:variable("@Attribute")])[1]', 'varchar(max)') 

दो स्तरों में local-name() का उपयोग कर अलग-अलग वैरिएबल में माता पिता के नोड नाम और विशेषता प्रदान करें।

declare @Node varchar(max) 
declare @Attribute varchar(max) 

set @Attribute = 'Word' 
set @Node = 'Keyword' 
select @xml.value('(/EventSpecificData 
        /*[local-name() = sql:variable("@Node")] 
        /*[local-name() = sql:variable("@Attribute")])[1]', 'varchar(max)') 

nodes को पैरामीटर के बाद से एक स्ट्रिंग शाब्दिक यह इस को हल करने के गतिशील एसक्यूएल उपयोग करने के लिए आमंत्रित किया है रहना होगा। यह आपकी मूल चर सामग्री के साथ काम करने के लिए ऐसा कुछ दिख सकता है।

set @Attribute = 'Keyword/Word' 
declare @SQL nvarchar(max) 
set @SQL = 'select @xml.value(''(/EventSpecificData/'[email protected]+')[1]'', ''varchar(max)'')' 
exec sp_executesql @SQL, N'@xml xml', @xml 

लेकिन आपको लगता है कि के बारे में पता होना चाहिए, अगर आप इस का उपयोग आप विस्तृत SQL इंजेक्शन हमलों के लिए खुला है। उस के साथ गतिशील एसक्यूएल निष्पादित आप दो परिणाम सेट दे देंगे

set @Attribute = 'Keyword/Word)[1]'', ''varchar(max)'') select @@version --' 

: कुछ कुटिल अंतिम-उपयोगकर्ता एक विशेषता स्ट्रिंग है कि इस तरह दिखता है के साथ आ सकता है। select @@version कुछ हानिरहित कोड दिखाने के लिए बस है लेकिन यह वहां बहुत खराब चीजें हो सकती है।

आप SQL इंजेक्शन हमले को रोकने के लिए quotename() का उपयोग कर सकते हैं। यह कम से कम मेरे द्वारा किए गए प्रयास को रोक देगा।

set @Attribute = 'Keyword/Word' 
set @SQL = 'select @xml.value('+quotename('(/EventSpecificData/'[email protected]+')[1]', '''')+', ''varchar(max)'')' 
exec sp_executesql @SQL, N'@xml xml', @xml 

क्या अंतिम संस्करण quotename() सुरक्षित है? Erland Sommarskog The Curse and Blessings of Dynamic SQL द्वारा इस आलेख पर एक नज़र डालें।

उद्धरण:

quotename() और quotestring() के साथ

तो, हम एसक्यूएल इंजेक्शन की तुलना में अच्छा संरक्षण है के रूप में हम parameterised आदेशों के साथ है? शायद। मैं को एसक्यूएल इंजेक्ट करने के किसी भी तरीके से नहीं जानता जो उद्धरण() या उद्धरण() के माध्यम से फिसल जाता है। फिर भी, आप SQL स्ट्रिंग में उपयोगकर्ता इनपुट को इंटरपोल कर रहे हैं, जबकि पैरामीटरयुक्त आदेशों के साथ, आप नहीं करते हैं।

1

स्ट्रिंग को संयोजित करने का प्रयास करें।

set @value = @xmlPath.value('(/EventSpecificData/' + @attribute + ')[1]', 'varchar(max)') 

अपडेट किया गया जवाब:

के ऑपरेशन CASE'ing कोशिश करते हैं।

SELECT @value = CASE @attribute 
     WHEN 'word' THEN [word] 
     WHEN 'occurrence' THEN [occurrence] 
     WHEN 'context' THEN [context] 
     END AS [value] 
FROM 
(
    SELECT x.u.value('(/EventSpecificData/Keyword/Word)[1]', 'varchar(max)') AS [word] 
     , x.u.value('(/EventSpecificData/Keyword/Occurrence)[1]', 'varchar(max)') AS [word] 
     , x.u.value('(/EventSpecificData/Keyword/Context)[1]', 'varchar(max)') AS [word] 
    FROM @xmlPath.nodes('/EventSpecificData') x(u) 
) a 
+1

प्रतिक्रिया के लिए धन्यवाद। जब मैं ऐसा करता हूं, तो मुझे संदेश मिलता है "एक्सएमएल डेटा प्रकार विधि" मान "का तर्क 1 एक स्ट्रिंग अक्षर होना चाहिए।" चूंकि पहला तर्क एक XQuery है। – user1200083

+1

@ user1200083: वह त्रुटि संदेश यह सब कहता है - आपके पास एक स्ट्रिंग अक्षर होना चाहिए - आपके पास एक चर नहीं हो सकता है। –

+0

ठीक है, इसलिए मैं इस तरह के शाब्दिक में चर और एसक्यूएल चर का उपयोग कर सकता हूं: xmlPath.value ('(*/* [स्थानीय-नाम() = एसक्यूएल: चर ("विशेषता 1")]] [1]', 'वर्कर (MAX) ') यह मानते हुए कि विशेषता 1' कीवर्ड 'है। हालांकि, अगर मैं 'कीवर्ड/वर्ड' में विशेषता 1 सेट करता हूं तो यह कोई परिणाम नहीं देता है। आगे के स्लैश के साथ इसका कुछ संबंध है, क्योंकि xmlPath.value ('(*/* [स्थानीय-नाम() = एसक्यूएल: चर ("विशेषता 1")]/वर्ड) [1]', 'वर्कर (MAX) ') काम करेगा। – user1200083