Ошибка SQL при выполнении оператора update с регулярным выражением через xmlquery на db2-luw - PullRequest
0 голосов
/ 21 октября 2019

Имеется таблица базы данных TABLE1 со столбцом COLUMN1 типа VARCHAR (1020). Мне нужно переформатировать некоторые данные из формата переменной длины в новый формат фиксированной длины (хеши удаляются, числа остаются дополненными нулями до длины 10):

например: из "123 # 456 # 789"into" 000000012300000004560000000789 ".

Выполнение данного оператора sql приводит к следующему сообщению об ошибке, которое не очень полезно и указывает только на разорванное соединение:

Произошла ошибкаво время выполнения SQL-запроса

Ursache: SQL-Fehler [08001]: [jcc] [t4] [2030] [11211] [4.22.29] Управление операциями в сокете, посвященное Socketaingabedatenstrom или Socketausgabedatenstromist ein Kommunikationsfehler aufgetreten.

Fehlerposition: Reply.fill () - недостаточно данных (-1). Nachricht: Unzureichende Daten. ERRORCODE = -4499, SQLSTATE = 08001

Я работаю над базой данных DB2-LUW 11.1 v10.5.0.5, где регулярные выражения не поддерживаются, кроме как в xmlqueries.

Когда я заменяю второй оператор return на «return xs: string ($ COLUMN1)», оператор выполняется нормально. Так что это не похоже на синтаксическую ошибку.

Я нашел некоторую информацию о том, что порядок операторов let не фиксирован. Поэтому я попытался удалить логику if / then / else, и это всегда приводило к одним и тем же результатам, поэтому, похоже, это тоже не проблема.

UPDATE TABLE1
SET COLUMN1 = xmlcast(xmlquery(
        '
        if (fn:matches( $COLUMN1,"(\d{0,10})#(\d{1,10})#(\d{1,10})")) 
            then
                xs:string($COLUMN1)
            else
                let $part1A := fn:replace($COLUMN1, "(\d{0,10})#(\d{1,10})#(\d{1,10})", "$1", "i")
                let $part1B := fn:string-join(("0000000000", $part1A), "")
                let $part1C := fn:substring($part1B, fn:string-length($part1B) - 9)

                let $part2A := fn:replace($COLUMN1, "(\d{0,10})#(\d{1,10})#(\d{1,10})", "$2", "i")
                let $part2B := fn:string-join(("0000000000", $part2A), "")
                let $part2C := fn:substring($part2B, fn:string-length($part2B) - 9)

                let $part3A := fn:replace($COLUMN1, "(\d{0,10})#(\d{1,10})#(\d{1,10})", "$3", "i")
                let $part3B := fn:string-join(("0000000000", $part3A), "")
                let $part3C := fn:substring($part3B, fn:string-length($part3B) - 9)

                let $result := fn:string-join(($part1C, $part2C, $part3C), "")

                return xs:string($result)
        '
        passing COLUMN1 AS "COLUMN1"
    ) AS VARCHAR(1020))
    WHERE COLUMN1 IS NOT NULL AND LENGTH(COLUMN1 ) > 0;

Ожидалось, что вместо этого будет успешно выполнено обновление sql. ошибки, которая приводит к разрыву соединения с базой данных.

Ответы [ 2 ]

1 голос
/ 21 октября 2019

Db2 11.1 поддерживает функции регулярных выражений вне функций XML

Например, REGEXP_LIKE

https://www.ibm.com/support/knowledgecenter/en/SSEPGG_11.1.0/com.ibm.db2.luw.sql.ref.doc/doc/r0061494.html

Итак, я бы использовал UPDATE на основе чего-то вродеэто

SELECT
   RIGHT('000000000' || REGEXP_EXTRACT(t,'(\d{0,10})#(\d{1,10})#(\d{1,10})',1,1,'',1),10)
|| RIGHT('000000000' || REGEXP_EXTRACT(t,'(\d{0,10})#(\d{1,10})#(\d{1,10})',1,1,'',2),10)
|| RIGHT('000000000' || REGEXP_EXTRACT(t,'(\d{0,10})#(\d{1,10})#(\d{1,10})',1,1,'',3),10)
FROM
    TABLE(VALUES('test123#456#789data')) AS T(T)

, которое возвращает

 1
 ------------------------------
 000000012300000004560000000789
0 голосов
/ 30 октября 2019

Вот решение, которое работает для меня.

Первый шаг: Проблема была \ d в fn.matches () работает, но не работает в fn: replace (),Мне пришлось заменить \ d на [0-9].

SELECT COLUMN1 AS SOURCE, xmlcast(xmlquery(
        '
        if (not(fn:matches( $COLUMN1,"(^\d{0,10})#(\d{1,10})#(\d{1,10})$"))) 
            then
                xs:string($COLUMN1)
            else
                let $part1A := fn:replace($COLUMN1, "([0-9]{0,10})#([0-9]{1,10})#([0-9]{1,10})", "$1", "i")
                let $part1B := fn:string-join(("0000000000", $part1A), "")
                let $part1C := fn:substring($part1B, fn:string-length($part1B) - 9)

                let $part2A := fn:replace($COLUMN1, "([0-9]{0,10})#([0-9]{1,10})#([0-9]{1,10})", "$2", "i")
                let $part2B := fn:string-join(("0000000000", $part2A), "")
                let $part2C := fn:substring($part2B, fn:string-length($part2B) - 9)

                let $part3A := fn:replace($COLUMN1, "([0-9]{0,10})#([0-9]{1,10})#([0-9]{1,10})", "$3", "i")
                let $part3B := fn:string-join(("0000000000", $part3A), "")
                let $part3C := fn:substring($part3B, fn:string-length($part3B) - 9)

                let $result := fn:string-join(($part1C, $part2C, $part3C), "")

                return xs:string($result)
        '
        passing COLUMN1 AS "COLUMN1"
    ) AS VARCHAR(1020)) AS REPLACEDBY
FROM
    TABLE(VALUES('123#456#789'),('test123#456#789data')) AS TABLE1(COLUMN1);

возвращает

SOURCE              | REPLACEDBY
---------------------------------------------
123#456#789         | 000000012300000004560000000789
test123#456#789data | test123#456#789data

Второй шаг: Избегание процедурной логики приводит к

SELECT 
    COLUMN1 AS SOURCE,
    RIGHT('000000000' || xmlcast(xmlquery('fn:replace($COLUMN1, "([0-9]{0,10})#([0-9]{1,10})#([0-9]{1,10})", "$1", "i")' passing COLUMN1 AS "COLUMN1") AS VARCHAR(10)), 10)
    || RIGHT('000000000' || xmlcast(xmlquery('fn:replace($COLUMN1, "([0-9]{0,10})#([0-9]{1,10})#([0-9]{1,10})", "$2", "i")' passing COLUMN1 AS "COLUMN1") AS VARCHAR(10)), 10)
    || RIGHT('000000000' || xmlcast(xmlquery('fn:replace($COLUMN1, "([0-9]{0,10})#([0-9]{1,10})#([0-9]{1,10})", "$3", "i")' passing COLUMN1 AS "COLUMN1") AS VARCHAR(10)), 10)
    AS REPLACEDBY
FROM
    TABLE(VALUES('123#456#789'),('test123#456#789data'),('0#0#0')) AS TABLE1(COLUMN1)
WHERE 
    0 <> xmlcast(xmlquery('fn:matches($COLUMN1,"(^\d{0,10})#(\d{1,10})#(\d{1,10})$")' passing COLUMN1 AS "COLUMN1") AS INTEGER);

возвращает

SOURCE              | REPLACEDBY
---------------------------------------------
123#456#789         | 000000012300000004560000000789
0#0#0               | 000000000000000000000000000000
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...