2012-03-06 2 views
1

У меня есть XML, который я хочу, чтобы это было извлекали с помощью OpenXML в SQL ServerИзвлечение данных из XML с помощью OpenXML в SQL Server

Вот пример XML

<row> 
    <student_token>7</student_token> 
    <student_ssn>552</student_ssn> 
    <alternate_id>20</alternate_id> 
    <old_ssn xsi:nil="true" /> 
    <alien_num xsi:nil="true" /> 
    <last_name>A</last_name> 
    <first_name>B</first_name> 
    <middle_init xsi:nil="true" /> 
    <drivers_license_num xsi:nil="true" /> 
    <gpa_highschool xsi:nil="true" /> 
    <created_dt>2006-07-13T11:15:08.320</created_dt> 
    <created_how>4</created_how> 
    <modified_dt>2008-02-14T00:00:00</modified_dt> 
    <modified_by>4</modified_by> 
    <primary_street2 xsi:nil="true" /> 
    <primary_street3 xsi:nil="true" /> 
    <primary_country xsi:nil="true" /> 
    <email_address xsi:nil="true" /> 
    <address_start_dt xsi:nil="true" /> 
    <address_end_dt xsi:nil="true" /> 
    <entrance_iv_dt xsi:nil="true" /> 
    <entrance_iv_by xsi:nil="true" /> 
    <exit_iv_dt>2006-11-02T00:00:00</exit_iv_dt> 
    <exit_iv_by>156</exit_iv_by> 
    <foreign_address_indicator>N</foreign_address_indicator> 
    <foreign_postal_code xsi:nil="true" /> 
    <pin>J27841</pin> 
    <web_id>J08614 </web_id> 
    <prior_name xsi:nil="true" /> 
    <orig_eps xsi:nil="true" /> 
    <web_role>STU1</web_role> 
    <heal_limit_flag>N</heal_limit_flag> 
    <email_address_2>[email protected]</email_address_2> 
    <cellular_telephone>415</cellular_telephone> 
    <alt_loan_debt xsi:nil="true" /> 
    <web_last_login xsi:nil="true" /> 
    <foreign_country_code xsi:nil="true" /> 
    <entrance_iv_dt_grad_plus xsi:nil="true" /> 
    <entrance_iv_by_grad_plus xsi:nil="true" /> 
    <failed_logins>0</failed_logins> 
    <hispanic xsi:nil="true" /> 
    <race xsi:nil="true" /> 
    <primary_phone_number_intl xsi:nil="true" /> 
    <security_version>0</security_version> 
    <failed_challenge_response>0</failed_challenge_response> 
    <require_pin_reset xsi:nil="true" /> 
</row> 

Запрос должен черпать в 3 поля для каждой строки

  1. FieldName
  2. FieldValue
  3. IsNull

Например, первая строка должна быть

  • Имя_поля = student_token - имя узла будет имя поля
  • FieldValue = 7
  • IsNull = ложь - IsNull основана на атрибут xsi: nil = "true"

Как это сделать? Любая помощь будет оценена по достоинству.

Благодаря

+0

Имя тега является FieldName и IsNull основан на Attribute XSI: ноль = «истинный» – Rush

+0

Результат должен взять имя элемента из каждого узла и возвратить это как имя поля. Например, первое имя поля строки будет student_token, а следующий будет student_ssn, а следующий будет alternate_id .... – Rush

+0

Вы имеете в виду использование первого имени элемента и использование этого как имя поля? Есть несколько xsi: ноль. – Paparazzi

ответ

6

Образцы данных с добавленным пространством имен.

declare @xml xml 
set @xml = 
'<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <student_token>7</student_token> 
    <student_ssn>552</student_ssn> 
    <alternate_id>20</alternate_id> 
    <old_ssn xsi:nil="true" /> 
    <alien_num xsi:nil="true" /> 
    <last_name>A</last_name> 
    <first_name>B</first_name> 
    <middle_init xsi:nil="true" /> 
    <drivers_license_num xsi:nil="true" /> 
    <gpa_highschool xsi:nil="true" /> 
    <created_dt>2006-07-13T11:15:08.320</created_dt> 
    <created_how>4</created_how> 
    <modified_dt>2008-02-14T00:00:00</modified_dt> 
    <modified_by>4</modified_by> 
    <primary_street2 xsi:nil="true" /> 
    <primary_street3 xsi:nil="true" /> 
    <primary_country xsi:nil="true" /> 
    <email_address xsi:nil="true" /> 
    <address_start_dt xsi:nil="true" /> 
    <address_end_dt xsi:nil="true" /> 
    <entrance_iv_dt xsi:nil="true" /> 
    <entrance_iv_by xsi:nil="true" /> 
    <exit_iv_dt>2006-11-02T00:00:00</exit_iv_dt> 
    <exit_iv_by>156</exit_iv_by> 
    <foreign_address_indicator>N</foreign_address_indicator> 
    <foreign_postal_code xsi:nil="true" /> 
    <pin>J27841</pin> 
    <web_id>J08614 </web_id> 
    <prior_name xsi:nil="true" /> 
    <orig_eps xsi:nil="true" /> 
    <web_role>STU1</web_role> 
    <heal_limit_flag>N</heal_limit_flag> 
    <email_address_2>[email protected]</email_address_2> 
    <cellular_telephone>415</cellular_telephone> 
    <alt_loan_debt xsi:nil="true" /> 
    <web_last_login xsi:nil="true" /> 
    <foreign_country_code xsi:nil="true" /> 
    <entrance_iv_dt_grad_plus xsi:nil="true" /> 
    <entrance_iv_by_grad_plus xsi:nil="true" /> 
    <failed_logins>0</failed_logins> 
    <hispanic xsi:nil="true" /> 
    <race xsi:nil="true" /> 
    <primary_phone_number_intl xsi:nil="true" /> 
    <security_version>0</security_version> 
    <failed_challenge_response>0</failed_challenge_response> 
    <require_pin_reset xsi:nil="true" /> 
</row>' 

Использование openxml.

declare @idoc int 
exec sp_xml_preparedocument @idoc out, @xml, '<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>' 

select FieldName, 
     FieldValue, 
     isnull([IsNull], 0) 
from openxml(@idoc, '/row/*',1) 
    with (
     FieldName varchar(50) '@mp:localname', 
     FieldValue varchar(50) '.', 
     [IsNull] bit   '@xsi:nil' 
     ) 

exec sp_xml_removedocument @idoc 

Использование типа данных XML:

;with xmlnamespaces('http://www.w3.org/2001/XMLSchema-instance' as ns) 
select T.N.value('local-name(.)', 'varchar(50)') as FieldName, 
     T.N.value('.', 'varchar(50)') as FieldValue, 
     isnull(T.N.value('@ns:nil', 'bit'), 0) as [IsNull] 
from @xml.nodes('/row/*') as T(N) 
+0

@marc_s - Является ли URL одинаковым в XML, как в выражении 'sp_xml_preparedocument'? –

+1

Упс - нет! :-) Я сам поставил себе все, что угодно - конечно, это не соответствует вашей настройке! :-) Извините, мой плохой ..... работает как очарование сейчас! –

2

Не уверен, что если у вас есть, что XML в качестве переменной SQL или внутри таблицы - вопрос очень неясный .....

Если у вас есть как переменная SQL, а затем попробовать что-то как это (примечание: вы должны объявить префикс xsi каким-то образом - иначе процессор XML в SQL Server не будет даже смотреть на ваш XML-документ):

DECLARE @input XML = '<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <student_token>7</student_token> 
    <student_ssn>552</student_ssn> 
    <alternate_id>20</alternate_id> 
    <old_ssn xsi:nil="true" /> 
    ......... 
</row>' 

;WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema-instance' as xsi) 
SELECT 
FieldName = T.C.value('local-name(.)', 'varchar(50)'), 
FieldValue = T.C.value('(.)[1]', 'varchar(500)'), 
IsNIL = ISNULL(T.C.value('(@xsi:nil)[1]', 'bit'), 0) 
FROM 
@Input.nodes('/row/*') AS T(C) 

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

FieldName  FieldValue IsNIL 
student_token 7   0 
student_ssn  552  0 
alternate_id  20   0 
old_ssn      1 
..... 

Конечно, все выходные будет типа varchar(500) сейчас в FieldValue колонке ....

Обновлено мой ответ, основанный на ответ Микаэля Эрикссона , чтобы включить обработку IsNIL. Спасибо Микаэлю за вдохновение! Вы заслуживаете одобрения и одобрения!

+0

Причиной использования OpenXml была производительность. Разве это не медленнее, чем openxml? – Rush

+0

@ Rush - Я думаю, что это был бы интересный вопрос о SO. Некоторое время я был в списке дел, чтобы проверить, что является самым быстрым. Я читал, что они должны быть почти одинаковыми, но ... требует некоторого тестирования. –

+0

@ Rush: нет, не обязательно. Оба подхода имеют свои плюсы и минусы, но OpenXML определенно более ресурсоемкий (с вызовом 'sp_xml_preparedocument') и менее интуитивно понятный (по крайней мере, для меня) –