Синтаксический анализ XML: строка 1, символ 345, дублированный атрибут - PullRequest
0 голосов
/ 05 мая 2019

Я пытаюсь получить конкретное значение атрибута из столбца XML, но получаю ошибку

Синтаксический анализ XML: строка 1, символ 345, повторяющийся атрибут

Мой код:

select 
    ship_to_cust_num,
    tank_num,
    tank_capacity_qty,
    tank_pkg_type_code,
    COALESCE(REPLACE(CAST(CAST(b.tank_inspection AS NTEXT) AS XML).value('(/TankInspection/Questions/Question[@AASAQno="9"]/@QAns)[1]', 'VARCHAR(50)'), '#', ''), 0)
from 
    bulk_site_tank (nolock)b
where 
    convert(varchar, b.tank_inspection) != 'NULL'

1 Ответ

1 голос
/ 05 мая 2019

Простой ответ заключается в том, что ошибка говорит вам о проблеме. Но объясню дальше. Возьмите это простое утверждение:

DECLARE @xml varchar(MAX);

SET @XML = '
<root>
    <child>
        <element attribute="1">value</element>
        <element attribute="2" attribute="2">Another Value</element>
    </child>
</root>';

SELECT *
FROM (VALUES(CONVERT(xml, @XML)))V(X);

Если вы запустите это, вы получите ошибку:

Сообщение 9437, уровень 16, состояние 1, строка 11 Синтаксический анализ XML: строка 5, символ 46, повторяющийся атрибут

Не удивительно, как если бы вы смотрели, второй element узел имеет attribute, объявленный дважды.

<ч />

Итак, как это исправить?

Во-первых, это означает, что вы храните свои XML-данные как тип данных, отличный от типа данных xml. XML должен храниться с использованием типа данных xml (это именно то, для чего он предназначен), и в нем может храниться только действительный XML; в результате вы не смогли бы вставить неверный XML в строку и не оказались бы в этой позиции. Как и вы, есть только одна вещь, которую вы можете сделать; найти все «плохие» строки:

SELECT tank_inspection
FROM bulk_site_tank
WHERE TRY_CONVERT(xml,tank_inspection) IS NULL
  AND tank_inspection IS NOT NULL;

Затем проверьте каждую строку, возвращенную в указанном выше наборе данных, и исправьте данные. Сделайте это действительным XML. После этого исправьте ваш тип данных:

ALTER TABLE bulk_site_tank ALTER COLUMN tank_inspection xml;

Теперь все в формате XML, вы можете исправить свой запрос:

SELECT ship_to_cust_num,
       tank_num,
       tank_capacity_qty,
       tank_pkg_type_code,
       REPLACE(b.tank_inspection.value('(/TankInspection/Questions/Question[@AASAQno="9"]/@QAns)[1]', 'varchar(50)'), '#', '') --AS ?
FROM bulk_site_tank b
WHERE b.tank_inspection IS NOT NULL;

Заметьте, я изменил синтаксис ANSI_NULL и избавился от NOLOCK (так как я предполагаю, что вы не знаете, что он на самом деле здесь делает). Выражения CAST / CONVERT тоже пропали, и я удалил COALESCE. Поскольку ваше выражение value возвращает varchar(50), а COALESCE имеет 0 для второго параметра. Это неявно приведёт значение, возвращённое из XML, к int и, вероятно, приведет к ошибке преобразования.

Боюсь, что вы должны очистить свои данные, но никто больше не может вам здесь помочь, я боюсь. Это только одна из причин, по которой неправильный выбор типов данных является проблемой; как если бы использовался правильный тип данных, то, как я уже говорил, неверный XML никогда не мог быть вставлен.

Удачи!

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