SQL Server 2008 में XML फ़ील्ड से मानों का चयन करें


112

बस अपने XML क्षेत्र को देखते हुए, मेरी पंक्तियाँ इस तरह दिखती हैं:

<person><firstName>Jon</firstName><lastName>Johnson</lastName></person>
<person><firstName>Kathy</firstName><lastName>Carter</lastName></person>
<person><firstName>Bob</firstName><lastName>Burns</lastName></person>

ध्यान दें कि ये मेरी तालिका में तीन पंक्तियाँ हैं।

मैं एक तालिका के रूप में एक SQL परिणाम वापस करना चाहते हैं

Jon  | Johnson
Kathy| Carter
Bob  | Burns

कौन सी क्वेरी इसे पूरा करेगी?


क्या xml में सभी तत्वों को प्राप्त करने का कोई तरीका नहीं है? आपको एक-एक करके बताना होगा? यह वास्तव में कठिन उपवास करता है। आप "टेबल से चयन करें" कर सकते हैं, ऐसा लगता है जैसे आप "xml से * का चयन करें" करने में सक्षम होना चाहिए। आप चाहते हैं कि हर एक तत्व को निर्दिष्ट किए बिना।
कीथ टायलर

जवाबों:


157

यह देखते हुए कि XML क्षेत्र का नाम 'xmlField' है ...

SELECT 
[xmlField].value('(/person//firstName/node())[1]', 'nvarchar(max)') as FirstName,
[xmlField].value('(/person//lastName/node())[1]', 'nvarchar(max)') as LastName
FROM [myTable]

16
यदि xmlField में एक से अधिक <व्यक्ति> तत्व हों तो आपको .nodes () और क्रॉस का उपयोग करना चाहिए।
रेमस रूसु

SQL Server 2008 R2 एक्सप्रेस, ने मुझे इस त्रुटि को आपके समाधान के साथ लौटाया The XQuery syntax '/function()' is not supported.:; दूसरी ओर @Remus Rusanu यह करने के लिए लगता है :)
RMiranda

2
विचित्र। यह 102 बार मतदान किया गया है, लेकिन यह उत्तर केवल पहले XML रिकॉर्ड से डेटा देता है । और यह कुछ [myTable] तालिका को संदर्भित करता है ... यह कहां से आया है?
माइक गल्डहिल

मैंने कई बार यह कोशिश की है और कभी भी यह काम नहीं किया है। मेरा XML है <BAM><Type>Electrical</Type><BaIds><a:int>7330</a:int></BaIds></BAM>, मेरा चयन है select e.MessageData.value('(/BAM/Type)[1]', 'varchar(100)')। मैं भी चयन की कोशिश की है e.MessageData.value('(/BAM/Type/node())[1]', 'varchar(100)'), और '(//Type/node())[1]', '(./Type)[1]', और हर दूसरे संयोजन मैं के बारे में सोच सकते हैं। सभी मैं कभी भी प्राप्त है NULL
JonathanPeel

1
@MikeGledhill यह मेरे लिए ठीक कई XML रिकॉर्ड से मान देता है। ओपी द्वारा प्रदान की जाने वाली तालिका का एकमात्र नाम "माई टेबल" :)
पॉल

123

यह देखते हुए कि XML डेटा एक टेबल 'टेबल' से आता है और इसे एक कॉलम 'फ़ील्ड' में संग्रहीत किया जाता है: XML विधियों का उपयोग करें , मानों को निकालें xml.value(), प्रोजेक्ट नोड्स के साथ xml.nodes(), CROSS APPLYशामिल होने के लिए उपयोग करें:

SELECT 
    p.value('(./firstName)[1]', 'VARCHAR(8000)') AS firstName,
    p.value('(./lastName)[1]', 'VARCHAR(8000)') AS lastName
FROM table 
    CROSS APPLY field.nodes('/person') t(p)

आप कर सकते हैं खाई nodes()और cross applyप्रत्येक क्षेत्र वास्तव में एक तत्व 'व्यक्ति' है या नहीं। यदि XML एक वैरिएबल है जिसे आप चुनते हैं FROM @variable.nodes(...)और आपको इसकी आवश्यकता नहीं है cross apply


1
मुझे आश्चर्य है कि यह तरीका कितना कारगर है और क्या बेहतर तरीका है। XPath परिणामों के साथ CROSS APPLY काम्बिनेशन ऐसा लगता है कि इसके परिणामस्वरूप काफी संसाधन भूखे प्रश्न हो सकते हैं।
Redcalx

1
@thelocster: यह सामान्य डेटा एक्सेस से अलग नहीं है। XML प्रदर्शन में सुधार के लिए तकनीकों को अच्छी तरह से प्रलेखित किया गया है। msdn.microsoft.com/en-us/library/ms345118%28SQL.90%29.aspx
Remus Rusanu

2
ध्यान रखें कि यदि आपके XML में xmlns नामस्थान परिभाषित हैं, तो आपको ऊपर दिए गए XQuery (XPath) अभिव्यक्ति में परिभाषित करने की आवश्यकता होगी। उदाहरण के लिए stackoverflow.com/a/1302150/656010 देखें ।
टॉम वेनसन

थोड़ा अलग जो मुझे चाहिए था, लेकिन यह एक समस्या का एक सही समाधान था जो मुझे हो रहा था जो एक XML कॉलम के साथ कई पंक्तियाँ थीं - मैं पंक्तियों के माध्यम से लूप करना चाहता था और XML कॉलम के भीतर से डेटा फ़ील्ड्स को बाहर निकालना और उन्हें अंदर रखना एक सम्मिलित कथन। तो 5 पंक्तियाँ, XML क्षेत्र में डेटा के 3 स्तंभों के लिए प्रत्येक = 15 आवेषण, सही।
दान रिचारडसन

17

यह पोस्ट मेरी समस्या को हल करने में मददगार थी जिसका थोड़ा अलग XML प्रारूप है ... मेरे XML में निम्न उदाहरण की तरह कुंजियों की एक सूची है और मैं DeleteKatch नामक तालिका में SourceKeys कॉलम में XML संग्रहीत करता हूं:

<k>1</k>
<k>2</k>
<k>3</k>

तालिका बनाएं और इसे कुछ डेटा के साथ आबाद करें:

CREATE TABLE dbo.DeleteBatch (
    ExecutionKey INT PRIMARY KEY,
    SourceKeys XML)

INSERT INTO dbo.DeleteBatch ( ExecutionKey, SourceKeys )
SELECT 1, 
    (CAST('<k>1</k><k>2</k><k>3</k>' AS XML))

INSERT INTO dbo.DeleteBatch ( ExecutionKey, SourceKeys )
SELECT 2, 
    (CAST('<k>100</k><k>101</k>' AS XML))

यहाँ XML से कुंजियों का चयन करने के लिए मेरी SQL है:

SELECT ExecutionKey, p.value('.', 'int') AS [Key]
FROM dbo.DeleteBatch
    CROSS APPLY SourceKeys.nodes('/k') t(p)

यहां देखें क्वेरी के नतीजे ...

निष्पादन कुंजी
1 1
१ २
1 3
२ १००
२ १०१

9

यह आपके प्रश्न का उत्तर दे सकता है:

select cast(xmlField as xml) xmlField into tmp from (
select '<person><firstName>Jon</firstName><lastName>Johnson</lastName></person>' xmlField
union select '<person><firstName>Kathy</firstName><lastName>Carter</lastName></person>'
union select '<person><firstName>Bob</firstName><lastName>Burns</lastName></person>'
) tb

SELECT
    xmlField.value('(person/firstName)[1]', 'nvarchar(max)') as FirstName
    ,xmlField.value('(person/lastName)[1]', 'nvarchar(max)') as LastName
FROM tmp

drop table tmp

6

Blimey। यह वास्तव में उपयोगी धागा था।

मुझे अभी भी इनमें से कुछ सुझाव भ्रामक लगे। जब भी मैं प्रयोग किया जाता है valueके साथ [1]स्ट्रिंग में, यह केवल पहले मान लिया गया होता। और कुछ सुझावों का उपयोग करके cross apply(मेरे परीक्षणों में) अभी बहुत अधिक डेटा वापस लाया गया।

तो, यहाँ मेरा सरल उदाहरण है कि आप किस तरह से एक xmlवस्तु का निर्माण करेंगे , फिर एक तालिका में इसके मूल्यों को पढ़ें।

DECLARE @str nvarchar(2000)

SET @str = ''
SET @str = @str + '<users>'
SET @str = @str + '  <user>'
SET @str = @str + '     <firstName>Mike</firstName>'
SET @str = @str + '     <lastName>Gledhill</lastName>'
SET @str = @str + '     <age>31</age>'
SET @str = @str + '  </user>'
SET @str = @str + '  <user>'
SET @str = @str + '     <firstName>Mark</firstName>'
SET @str = @str + '     <lastName>Stevens</lastName>'
SET @str = @str + '     <age>42</age>'
SET @str = @str + '  </user>'
SET @str = @str + '  <user>'
SET @str = @str + '     <firstName>Sarah</firstName>'
SET @str = @str + '     <lastName>Brown</lastName>'
SET @str = @str + '     <age>23</age>'
SET @str = @str + '  </user>'
SET @str = @str + '</users>'

DECLARE @xml xml
SELECT @xml = CAST(CAST(@str AS VARBINARY(MAX)) AS XML) 

--  Iterate through each of the "users\user" records in our XML
SELECT 
    x.Rec.query('./firstName').value('.', 'nvarchar(2000)') AS 'FirstName',
    x.Rec.query('./lastName').value('.', 'nvarchar(2000)') AS 'LastName',
    x.Rec.query('./age').value('.', 'int') AS 'Age'
FROM @xml.nodes('/users/user') as x(Rec)

और यहाँ उत्पादन है:

यहां छवि विवरण दर्ज करें

यह विचित्र सिंटेक्स है, लेकिन एक सभ्य उदाहरण के साथ, अपने स्वयं के SQL सर्वर फ़ंक्शन को जोड़ना काफी आसान है।

जिसके बारे में बोलते हुए, यहाँ इस प्रश्न का सही उत्तर है।

मान लें कि आपके पास अपना xml डेटा @xmlप्रकार के चर में है xml(जैसा कि ऊपर मेरे उदाहरण में प्रदर्शित किया गया है), यहां बताया गया है कि आप प्रश्न में उद्धृत xml से डेटा की तीन पंक्तियों को कैसे लौटाएंगे:

SELECT 
    x.Rec.query('./firstName').value('.', 'nvarchar(2000)') AS 'FirstName',
    x.Rec.query('./lastName').value('.', 'nvarchar(2000)') AS 'LastName'
FROM @xml.nodes('/person') as x(Rec)

यहां छवि विवरण दर्ज करें


मैं नहीं देखता कि यह कैसे सही उत्तर है। ओपी एक टेबल से एक कॉलम को क्वेरी करने के लिए कह रहा है जो कि XML का है, और उस स्थिति में आपको या तो उपयोग करना है [1], इंडेक्स ऑर्डिनल इसे 1 पंक्ति में वापस जाने के लिए मजबूर करता है, या आपको nodes()एक प्राप्त करने के लिए कॉलम को पार करना होगा संरचना जो इसके खिलाफ चल सकती है। आपका कोड बहुत सारे संशोधनों के बिना उस परिदृश्य में अनुवाद नहीं करता है। आप एक तालिका स्तंभ नहीं, एक चर का उपयोग कर रहे हैं। आप query()फ़ंक्शन का अति प्रयोग भी कर रहे हैं जो xml लौटाता है। उदाहरण के लिए आप बसx.Rec.value('(./firstName)[1]', 'nvarchar(2000)') AS FirstName
दावोस

3

यदि आप अपने XML को मूल तत्व में लपेटने में सक्षम हैं - तो कहें कि आपका समाधान निम्नलिखित है:

DECLARE @PersonsXml XML = '<persons><person><firstName>Jon</firstName><lastName>Johnson</lastName></person>
<person><firstName>Kathy</firstName><lastName>Carter</lastName></person>
<person><firstName>Bob</firstName><lastName>Burns</lastName></person></persons>'

SELECT  b.value('(./firstName/text())[1]','nvarchar(max)') as FirstName, b.value('(./lastName/text())[1]','nvarchar(max)') as LastName
FROM @PersonsXml.nodes('/persons/person') AS a(b)

यहां छवि विवरण दर्ज करें


3

MSSQL नियमित XPath नियमों का उपयोग करता है:

  • nodename "nodename" नाम के साथ सभी नोड्स का चयन करता है
  • / रूट नोड से चयन करता है
  • // दस्तावेज़ में मौजूदा नोड से नोड्स का चयन करता है जो चयन से मेल खाते हैं कि वे कहां हैं
  • । वर्तमान नोड का चयन करता है
  • .. वर्तमान नोड के जनक का चयन करता है
  • @ विशेषताओं का चयन करता है

W3Schools


2
SELECT 
cast(xmlField as xml).value('(/person//firstName/node())[1]', 'nvarchar(max)') as FirstName,
cast(xmlField as xml).value('(/person//lastName/node())[1]', 'nvarchar(max)') as LastName
FROM [myTable]

0

/ * यह उदाहरण स्कीमा के साथ XML चर का उपयोग करता है * /

IF EXISTS (SELECT * FROM sys.xml_schema_collections 
           WHERE name = 'OrderingAfternoonTea')
BEGIN
    DROP XML SCHEMA COLLECTION dbo.OrderingAfternoonTea 
END
GO

CREATE XML SCHEMA COLLECTION dbo.OrderingAfternoonTea AS
N'<?xml version="1.0" encoding="UTF-16" ?>
  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     targetNamespace="http://Tfor2.com/schemas/actions/orderAfternoonTea"
     xmlns="http://Tfor2.com/schemas/actions/orderAfternoonTea"
     xmlns:TFor2="http://Tfor2.com/schemas/actions/orderAfternoonTea"
     elementFormDefault="qualified"
     version="0.10"
   > 
    <xsd:complexType name="AfternoonTeaOrderType">
       <xsd:sequence>
         <xsd:element name="potsOfTea" type="xsd:int"/>
         <xsd:element name="cakes" type="xsd:int"/>
         <xsd:element name="fruitedSconesWithCream" type="xsd:int"/>
         <xsd:element name="jams" type="xsd:string"/>
      </xsd:sequence>
      <xsd:attribute name="schemaVersion" type="xsd:long" use="required"/>
    </xsd:complexType>

    <xsd:element name="afternoonTeaOrder"
                 type="TFor2:AfternoonTeaOrderType"/>

  </xsd:schema>' ;
GO

DECLARE @potsOfTea int;
DECLARE @cakes int;
DECLARE @fruitedSconesWithCream int;
DECLARE @jams nvarchar(128);

DECLARE @RequestMsg NVARCHAR(2048);
DECLARE @RequestXml XML(dbo.OrderingAfternoonTea);

set @potsOfTea = 5;
set @cakes = 7;
set @fruitedSconesWithCream = 25;
set @jams = N'medlar jelly, quince and mulberry';

SELECT @RequestMsg = N'<?xml version="1.0" encoding="utf-16" ?>
<TFor2:afternoonTeaOrder schemaVersion="10"
    xmlns:TFor2="http://Tfor2.com/schemas/actions/orderAfternoonTea">
    <TFor2:potsOfTea>' + CAST(@potsOfTea as NVARCHAR(20)) 
        + '</TFor2:potsOfTea>
    <TFor2:cakes>' + CAST(@cakes as NVARCHAR(20)) + '</TFor2:cakes>
    <TFor2:fruitedSconesWithCream>' 
        + CAST(@fruitedSconesWithCream as NVARCHAR(20))
        + '</TFor2:fruitedSconesWithCream>
    <TFor2:jams>' + @jams + '</TFor2:jams>
</TFor2:afternoonTeaOrder>';

SELECT @RequestXml  = CAST(CAST(@RequestMsg AS VARBINARY(MAX)) AS XML) ;

with xmlnamespaces('http://Tfor2.com/schemas/actions/orderAfternoonTea'
                    as tea)
select
    cast( x.Rec.value('.[1]/@schemaVersion','nvarchar(20)') as bigint )
        as schemaVersion,
    cast( x.Rec.query('./tea:potsOfTea')
               .value('.','nvarchar(20)') as bigint ) as potsOfTea,
    cast( x.Rec.query('./tea:cakes')
               .value('.','nvarchar(20)') as bigint )  as cakes,
    cast( x.Rec.query('./tea:fruitedSconesWithCream')
               .value('.','nvarchar(20)') as bigint ) 
      as fruitedSconesWithCream,
    x.Rec.query('./tea:jams').value('.','nvarchar(50)')  as jams
from @RequestXml.nodes('/tea:afternoonTeaOrder')  as x(Rec);

select @RequestXml.query('/*')
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.