Я вставил XML-файл в базу данных Postgresql и пытаюсь выполнить операцию XPATH над полем со сравнением дат, но она не работает. На официальном сайте Postgresql я узнал, что Postgresql использует Xpath1, а Xpath1 не поддерживает сравнение дат. Я попытался изменить свой запрос Xpath, чтобы использовать сравнение на основе строк, но он все равно не соответствует.
Входной Xpath:
//val:key[@modifiedDate>"2024-06-06"]
Поскольку прямое сравнение дат недоступно в Xpath1, я попробовал сравнение на основе строк.
Преобразованный Xpath:
//val:key[substring(@modifiedDate, 1, 10) > "2024-06-06"]
Но этот XPath также не соответствует, хотя соответствующий Xpath существует. Как мне создать свой Xpath, чтобы он соответствовал полю с датой.
Пример структуры XML, вставленной в таблицу.
<root xmlns:val = "http://some.uri">
<val:key modifiedDate = "2024-06-07T12:34:56">Key1</val:key>
<val:key modifiedDate = "2024-06-05T08:21:00">Key2</val:key>
<val:key modifiedDate = "2024-06-10T14:22:33">Key3</val:key>
<val:key modifiedDate = "2024-06-06T09:00:00">Key4</val:key>
</root>
Ожидаемый результат: мы сможем сопоставить этот XML, поскольку он имеет xpaths <val:key ModifiedDate="2024-06-07T12:34:56">Key1</val:key> и <val:key ModifiedDate="2024- 06-10T14:22:33">Key3</val:key>, поскольку их атрибуты ModifiedDate начинаются с дат позже, чем "2024-06-06".
SQL-запрос для воспроизведения проблемы:
CREATE TABLE xml_data (
id SERIAL PRIMARY KEY,
document XML
);
INSERT INTO xml_data (document)
VALUES ('<root xmlns:val = "http://some.uri">
<val:key modifiedDate = "2024-06-07T12:34:56">Key1</val:key>
<val:key modifiedDate = "2024-06-05T08:21:00">Key2</val:key>
<val:key modifiedDate = "2024-06-10T14:22:33">Key3</val:key>
<val:key modifiedDate = "2024-06-06T09:00:00">Key4</val:key>
</root>');
Запрос для фильтрации данных:
SELECT
id, document
FROM
xml_data
WHERE
xpath_exists('//val:key[substring(@modifiedDate, 1, 10) > "2024-06-06"]', document);
Задавая вопрос, вам необходимо предоставить минимальный воспроизводимый пример: (1) DDL и образец набора данных, т. е. таблицы CREATE плюс операторы SQL INSERT. (2) Что вам нужно сделать, то есть логику и попытку вашего кода реализовать ее в SQL. (3) Желаемый результат, основанный на примере данных в пункте 1 выше. (4) Ваша версия СУБД.
Изменил вопрос @YitzhakKhabinsky
Изменил вопрос @PepeNO
В предоставленном образце XML есть одна фундаментальная проблема: в нем нет объявления пространства имен XML. Это делает XML неправильно сформированным и непригодным для использования. Пожалуйста, исправьте это.
Добавьте <root xmlns:val = "http://some.uri">
, чтобы определить неопределенное пространство имен «val».
DOne, спасибо вам обоим
Учитывая , что
В XPath 1.0 нет оператора сравнения порядка строк. Оба «кошки» < «собака» и «кошка» > «собака» являются ложными, поскольку каждое из них представляет собой числовое значение. сравнение двух NaN.
Вы можете получить доступ к значениям в своем XML-документе и привести их к дате или метке времени, а затем выполнить сравнение таким образом (исправив отсутствующее пространство имен xmlns:val="http://some.uri", чтобы сделать его действительным):
select key, modified_date from
xmltable(xmlnamespaces('http://some.uri' as val),
'//val:key'
passing (select document from xml_data)
columns key varchar path 'text()',
modified_date timestamp path '@modifiedDate')
where modified_date>'2024-06-06';
Результат
Спасибо, я смог решить эту проблему с помощью XPath //val:key[number(translate(substring(@modifiedDate, 1, 10), "-", "")) < number("20240606")]
Как указывает Пепе Н О, использование оператора >
в выражении XPath преобразует операнды даты из строк в числа, но поскольку оба операнда содержат нечисловые символы, преобразование приведет к NaN
в обоих случаях.
Однако вы можете изменить выражение XPath, чтобы использовать функцию перевода XPath для преобразования дат в чисто числовые значения.
Например, выражение translate('2024-06-07T12:34:56', '-T:', '')
равно "20240607123456"
.
Спасибо, я смог решить эту проблему с помощью XPath //val:key[number(translate(substring(@modifiedDate, 1, 10), "-", "")) < number("20240606")]
Добавьте фиктивные данные и ожидаемые результаты, чтобы сообщество могло помочь.