2013-09-26 204 views
5

Sử dụng SQL 2012 & nhận XML được chuyển vào quy trình được lưu trữ phải nhập đầu vào đó & ghi một hàng vào mỗi mục trong đó một phần của XML được chuyển đến thủ tục được lưu trữ. XML trông giống như:SQL 2012 - lặp qua danh sách XML (thay thế tốt hơn cho vòng lặp WHILE)

<MyXML> 
    <MyMsg>My Text Message</MyMsg> 
    <MsgTime>2013-09-25 10:52:37.098</MsgTime> 
    <SendToList> 
    <SendTo>John</SendTo> 
    <SendTo>James</SendTo> 
    <SendTo>Rob</SendTo> 
    <SendTo>Pete</SendTo> 
    <SendTo>Sam</SendTo> 
    </SendToList> 
</MyXML> 

Đầu ra của thủ tục lưu trữ sẽ là 5 hàng chèn vào một bảng (một cho mỗi SendTo ở trên), và từng có giá trị như nhau trong MyMsgMsgTime trường trong bảng đó.

Tôi có thể nhận số đếm là SendTo và có thể lấy XML SendToList nhưng tôi không biết cách lặp qua nó để thực hiện chèn.

Tôi có thể sử dụng SQL sau đây để lấy nội dung trong XML.

SELECT 
x.value('(/MyXML/MyMsg)[1]', 'VARCHAR(1024)'), 
x.value('(/MyXML/MsgTime)[1]', 'DATETIME'), 
    @max = x.query('<e> { count(/MyXML/SendToList/SendTo) } </e>').value('e[1]','int'), 
    @mlst = x.query('/MyXML/SendTo') 
    FROM @XML_In.nodes('//MyXML') i(x) 

Hiện nay, tôi đang sử dụng các biến và một WHILE để lặp qua các mục trong SendToList, nhưng tôi biết có nhận được một cách tốt hơn.

SELECT @msgTo= @XML_In.value('(/MyXML/SendToList/SendTo[position()=sql:variable("@cnt")])[1]','VARCHAR(100)') 

Ở trên mang lại cho tôi giá trị của từng mục trong SendToList.
Nếu tôi chọn biến @mlst, tôi có thể thấy cấu trúc của XML mà tôi cần lặp lại.

<SendToList> 
    <SendTo>John</SendTo> 
    <SendTo>James</SendTo> 
    <SendTo>Rob</SendTo> 
    <SendTo>Pete</SendTo> 
    <SendTo>Sam</SendTo> 
</SendToList> 

Mặc dù WHILE hoạt động, nó đang thực hiện một lần chèn ngay sau thẻ còn lại. Tôi đã nghĩ rằng các phương pháp có sẵn sẽ có thể làm tất cả thay vì lặp nhưng tôi không biết đủ về cách sử dụng chúng để làm những gì tôi cần làm.

Sẽ đánh giá cao bất kỳ trợ giúp hoặc đề xuất nào.

Trả lời

12

Nếu bạn cần phải làm một cái gì đó mà đòi hỏi một vòng lặp (ví dụ, bạn muốn gửi email đến từng người nhận, hơn bạn có thể sử dụng một con trỏ:

declare cur cursor local fast_forward for 
    select 
     s.c.value('(text())[1]', 'nvarchar(max)') as SendTo, 
     m.c.value('(MyMsg/text())[1]', 'nvarchar(max)') as MyMsg, 
     m.c.value('(MsgTime/text())[1]', 'nvarchar(max)') as MsgTime 
    from @XML_In.nodes('MyXML') as m(c) 
     outer apply m.c.nodes('SendToList/SendTo') as s(c) 

open cur 
while 1 = 1 
begin 
    fetch cur into @SendTo, @MyMsg, @MsgTime 
    if @@fetch_status <> 0 break 

    --======================================= 
    -- do what you need here 
    --======================================= 
end 
close cur 
deallocate cur 

Nếu bạn chỉ muốn chèn hàng vào một số bảng, bạn có thể làm điều này trong một chèn đơn giản:

insert into <Your table> 
(
    SendTo, MyMsg, MsgTime 
) 
select 
    s.c.value('(text())[1]', 'nvarchar(max)') as SendTo, 
    m.c.value('(MyMsg/text())[1]', 'nvarchar(max)') as MyMsg, 
    m.c.value('(MsgTime/text())[1]', 'nvarchar(max)') as MsgTime 
from @XML_In.nodes('MyXML') as m(c) 
    outer apply m.c.nodes('SendToList/SendTo') as s(c) 

sql fiddle demo

+0

Tôi sẽ được chèn thẳng vào một bảng - ví dụ thứ hai của bạn làm việc tuyệt vời. Cảm ơn bạn! –

+0

Điều gì sẽ xảy ra nếu tôi muốn đọc dữ liệu và lưu nó vào một biến được hiển thị ở giao diện người dùng? http://stackoverflow.com/questions/26426412/how-to-ensure-the-sql-is-able-to-read-all-xml-tag-data – SearchForKnowledge

+0

Tùy chọn đầu tiên yêu cầu tôi khai báo SendTo, MyMsg, MsgTime – user3885927