SQL Server 2008 - переменная sql_variant в XML node.value - PullRequest
2 голосов
/ 09 сентября 2010

Пытаетесь понять, почему нельзя использовать sql_variant для типа значения при использовании функции узлов XML в SQL Server? У меня есть сценарий, в котором я буду динамически анализировать некоторые входные данные XML, и возможность использования sql_variant будет хорошей альтернативой необходимости присваивать переменную типа данных или выполнять поиск по sys.columns.

Пример:

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[XmlSourceTable]') AND type in (N'U'))
DROP TABLE [dbo].[XmlSourceTable]
GO
CREATE TABLE [dbo].[XmlSourceTable](
    [RecordId] [int] IDENTITY(1,1) NOT NULL,
    [XmlData] [xml] NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [RecordId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

DECLARE @XML XML ='<?xml version="1.0" ?>
<Root>
      <Person>
            <Name>Simon</Name>
            <Age>20</Age>
            <Skills>
                  <Skill>Cooking</Skill>
                  <Skill>Cleaning</Skill>
            </Skills>
      </Person>
      <Person>
            <Name>Peter</Name>
            <Age>21</Age>
            <Skills>
                  <Skill>Ironing</Skill>
            </Skills>
      </Person>
</Root>'

INSERT INTO XmlSourceTable(XmlData)
SELECT @XML

GO

SELECT * FROM XmlSourceTable
GO
SELECT
      pref.value('(Name/text())[1]', 'varchar(50)') as PersonName,
      pref.value('(Age/text())[1]', 'int') as PersonAge,
      pref.query('Skills') as PersonSkills
FROM  
      XmlSourceTable CROSS APPLY
      XmlData.nodes('/Root/Person') AS People(pref)

Так вместо:

SELECT * FROM XmlSourceTable
GO
SELECT
      pref.value('(Name/text())[1]', 'varchar(50)') as PersonName,
      pref.value('(Age/text())[1]', 'int') as PersonAge,
      pref.query('Skills') as PersonSkills
FROM  
      XmlSourceTable CROSS APPLY
      XmlData.nodes('/Root/Person') AS People(pref)

Было бы неплохо использовать:

SELECT * FROM XmlSourceTable
GO
SELECT
      pref.value('(Name/text())[1]', 'sql_variant') as PersonName,
      pref.value('(Age/text())[1]', 'sql_variantt') as PersonAge,
      pref.query('Skills') as PersonSkills
FROM  
      XmlSourceTable CROSS APPLY
      XmlData.nodes('/Root/Person') AS People(pref)

Но я получаю эту ошибку: Сообщение 9500, уровень 16, состояние 1, строка 1 Тип данных sql_variant), используемый в методе VALUE, недопустим.

В любом случае использовать sql_variant в функции узлов?

Спасибо

S

1 Ответ

3 голосов
/ 09 сентября 2010

sql_variant - это метатип, который хранит в значении фактический тип данных (int, char, float, date и т. Д.). Проблема в том, что XML-выражения не имеют тип: какой тип результата выражения XPath, например ('Name/text())[1]? Я понимаю, что вы можете утверждать, что , если XML имеет схему, можно определить тип схемы xs, связанный с этим узлом / атрибутом / элементом, но я бы сказал, что возможно вы могли бы выведите тип, и вы все еще останетесь с подавляющим большинством XML-документов без схемы, которые там используются ... Вот почему XML-методу .value() нужен тип, чтобы он мог привести найденный текст в XML в правильный тип.

Стоит отметить, что большинство значений XML можно извлечь как VARCHAR, что даст исходный текст XML для этого элемента / атрибута. Затем вы можете преобразовать текст в соответствующий столбец. Но я думаю, что то, что вы делаете сейчас (посмотрите на тип столбца, динамически создайте XPath / тип с правильным типом), будет лучше .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...