2013-08-09 1 views
1

У меня есть столбец в моей таблице с XML, который выглядит следующим образом:Синтаксический XML из отборного заявления

<Notes> <Note> 
    <Author>test</Author> 
    <AuthorInitials>JJJ</AuthorInitials> 
    <Contents>Test treatment notes 3</Contents> 
    <DateCreated>2013-07-17T14:43:00</DateCreated> 
    <DateModified>2013-07-17T14:43:00</DateModified> 
</Note> 
<Note> 
    <Author>test</Author> 
    <AuthorInitials>JJJ</AuthorInitials> 
    <Contents>This is the intial notes test for tasks</Contents> 
    <DateCreated>2013-07-17T14:36:00</DateCreated> 
    <DateModified>2013-07-17T14:36:00</DateModified> 
</Note> 

<Notes> <Note> 
    <Author>test</Author> 
    <AuthorInitials>JJJ</AuthorInitials> 
    <Contents>Test 4 of Task Notes</Contents> 
    <DateCreated>2013-07-17T14:57:00</DateCreated> 
    <DateModified>2013-07-17T14:57:00</DateModified> 
</Note> 
<Note> 
    <Author>test</Author> 
    <AuthorInitials>JJJ</AuthorInitials> 
    <Contents>This is the second note test for tasks</Contents> 
    <DateCreated>2013-07-17T14:37:00</DateCreated> 
    <DateModified>2013-07-17T14:37:00</DateModified> 
</Note> 

И я хочу, чтобы разобрать до конца и просто получить <Contents> часть его. Некоторые поля имеют несколько <Contents>, поэтому мне нужно иметь возможность вытащить все из них.

Я думал, что нужно использовать курсор и хранить результаты в таблице, но я все еще новичок в SQL Server, и я не думаю, что полностью их понимаю.

Вот что я в настоящее время:

DECLARE @temptable TABLE 
      (
       Category   varchar(5000), 
       Notes    varchar(5000) 
      ) 
    DECLARE @Contents  varchar(5000) 



    DECLARE c CURSOR FOR SELECT COMMENTS 
        FROM EVENT 
        WHERE COMMENTS <> '' 
        AND COMMENTS IS NOT NULL 
        AND ID = 1171438 

    OPEN c 

    FETCH NEXT FROM c INTO @Contents 

    WHILE (@@FETCH_STATUS = 0) 
    BEGIN 
     INSERT INTO @temptable (Category, Notes) 
     SELECT 'Notes', 
      SUBSTRING(COMMENTS, 
         (CHARINDEX('<Contents>', 
            COMMENTS)+10), 
         (CHARINDEX('</Contents>', 
            COMMENTS)-CHARINDEX('<Contents>', 
                       COMMENTS)-10)) 
     FROM Event 
     WHERE COMMENTS <> '' 
     AND COMMENTS IS NOT NULL 
     AND ID = 1171438 
     FETCH NEXT FROM c INTO @Contents 
    END 

    CLOSE c 
    DEALLOCATE c 

    SELECT * 
    FROM @temptable 

Но это только возвращает:

Notes | Test treatment notes 3 
Notes | Test 4 of Task Notes 
Notes | Test treatment notes 3 
Notes | Test 4 of Task Notes 

Любая идея, что я не хватает?

EDIT: Решение, которое работало:

DECLARE @temptable TABLE 
       (
        Category   varchar(5000), 
        Notes    XML 
       ) 
    INSERT INTO @temptable (Category, Notes) 
    SELECT 'Notes', 
      COMMENTS 
    FROM Event 
    WHERE COMMENTS <> '' 
     AND COMMENTS IS NOT NULL 
     AND ID = 1171438 

    SELECT Category, 
      Content = XNote.value('(Contents)[1]', 'varchar(5000)') 
    FROM @temptable 
    CROSS APPLY Notes.nodes('/Notes/Note') AS Xtbl(Xnote) 

ответ

1

Вы можете использовать очень простой и easy XQuery, IF ваш столбец имеет тип XML в SQL Server.

Попробуйте (также примечание: вы должны закрыть XML с действительным конечным тэгом!):

DECLARE @temptable TABLE (ID INT NOT NULL, Notes XML) 

INSERT INTO @temptable VALUES(1, '<Notes> <Note> 
    <Author>test</Author> 
    <AuthorInitials>JJJ</AuthorInitials> 
    <Contents>Test treatment notes 3</Contents> 
    <DateCreated>2013-07-17T14:43:00</DateCreated> 
    <DateModified>2013-07-17T14:43:00</DateModified> 
</Note> 
<Note> 
    <Author>test</Author> 
    <AuthorInitials>JJJ</AuthorInitials> 
    <Contents>This is the intial notes test for tasks</Contents> 
    <DateCreated>2013-07-17T14:36:00</DateCreated> 
    <DateModified>2013-07-17T14:36:00</DateModified> 
</Note></Notes>'), (2, '<Notes> <Note> 
    <Author>test</Author> 
    <AuthorInitials>JJJ</AuthorInitials> 
    <Contents>Test 4 of Task Notes</Contents> 
    <DateCreated>2013-07-17T14:57:00</DateCreated> 
    <DateModified>2013-07-17T14:57:00</DateModified> 
</Note> 
<Note> 
    <Author>test</Author> 
    <AuthorInitials>JJJ</AuthorInitials> 
    <Contents>This is the second note test for tasks</Contents> 
    <DateCreated>2013-07-17T14:37:00</DateCreated> 
    <DateModified>2013-07-17T14:37:00</DateModified> 
</Note></Notes>') 

SELECT 
    ID, 
    Content = XNote.value('(Contents)[1]', 'varchar(100)') 
FROM 
    @temptable 
CROSS APPLY 
    notes.nodes('/Notes/Note') AS XTbl(XNote) 

Это дает мне выход:

ID Content 
1 Test treatment notes 3 
1 This is the intial notes test for tasks 
2 Test 4 of Task Notes 
2 This is the second note test for tasks 

Там совершенно нет вам нужен курсор для работы с памятью и памятью!

+1

Ahh wow, не было этого в настоящее время! Спасибо! Делает это намного проще :-) – rjbogz

+0

Работал красиво. Добавлено, что работало выше. – rjbogz

0

SQL Server может использовать XPath/XQuery для извлечения данных из XML. Это гораздо лучше, чем то, что вы делаете.

В идеале вы должны хранить свои данные в формате XML и запускать такой запрос.

select 
    id, 
    tc.contents.value('.', 'nvarchar(500)') 
from yourtable t 
    cross apply 
    comments.nodes('/Notes/Note/Contents') as tc(contents) 

См http://technet.microsoft.com/en-us/library/ms188282.aspx

Если вы не можете изменить структуру данных (и я настоятельно рекомендую, что вы делаете), вы всегда можете сделать это

select tc.contents.value('.', 'nvarchar(500)') 
from (select CONVERT(xml, comments) c from yourtable) t 
    cross apply 
    c.nodes('/Notes/Note/Contents') as tc(contents)  
0
DECLARE @MyTable TABLE(
    Id INT IDENTITY(1,1) PRIMARY KEY, 
    XmlCol XML NOT NULL 
); 
INSERT @MyTable(XmlCol) 
VALUES(N'<Notes> <Note> 
    <Author>test</Author> 
    <AuthorInitials>JJJ</AuthorInitials> 
    <Contents>Test treatment notes 3</Contents> 
    <DateCreated>2013-07-17T14:43:00</DateCreated> 
    <DateModified>2013-07-17T14:43:00</DateModified> 
</Note> 
<Note> 
    <Author>test</Author> 
    <AuthorInitials>JJJ</AuthorInitials> 
    <Contents>This is the intial notes test for tasks</Contents> 
    <DateCreated>2013-07-17T14:36:00</DateCreated> 
    <DateModified>2013-07-17T14:36:00</DateModified> 
</Note> 
</Notes>'); 

SELECT *, 
     t.XmlCol.query(' 
      for $i in (/Notes/Note/Contents) 
       return $i 
     ') AS AllContent0, -- Only <Contents> elements 
     t.XmlCol.query(' 
      for $i in (/Notes/Note/Contents/text()) 
       return $i 
     ') AS AllContent1, -- Only text without separator 
     STUFF(CONVERT(NVARCHAR(4000),t.XmlCol.query(' 
      for $i in (/Notes/Note/Contents/text()) 
       return concat(",",$i) 
     ')),1,1,'') AS AllContent2 -- Only text with "," as separator 
FROM @MyTable t;