1

I have this xml on my db:

<requestXML>
  <headers>
    <name>Accept</name>
    <value>text/plain, application/json, application/*+json, */*</value>
  </headers>
  <method>PUT</method>
  <payload>{"timestamp":"1659167441820","orderIdentifierCode":"OC22004795","clientName":"XXXX","country":"XX","vatNumber":"XXXXXXXX","orderDate":"XX/XX/XXXX","orderState":"XX"}</payload>
<threadName>default task-xx</threadName>
<url>http://localhost:8080/service_name</url>
</requestXML>

I tried to perform a SELECT statement with XMLExists but with no results. What I need is to search into <payload> tag, inside those json body, the orderIdentifierCode value.

Here my SELECT:

SELECT * FROM EVDA.TETSIR_LOG_WS_PBE
    AS X
        WHERE XMLExists('$XML//requestXML/payload[orderIdentifierCode="OC22004795"]' passing X.T_RIC_XML AS "XML")
        AND D_TMS_REG BETWEEN '2022-07-27 00:00:00.000001' AND '2022-08-02 23:59:59.999999'
WITH UR;

This one, on the contrary, is working fine:

SELECT * FROM EVDA.TETSIR_LOG_WS_PBE
    AS X
        WHERE XMLExists('$XML//requestXML[method="PUT"]' passing X.T_RIC_XML AS "XML")
        AND D_TMS_REG BETWEEN '2022-07-27 00:00:00.000001' AND '2022-08-02 23:59:59.999999'
WITH UR;

I started to think that the first one is not well formatted or that something is missing due to complex value inside the tag <payload>.

Any guess?

Thanks in advance

Ad1Os
  • 11
  • 2

1 Answers1

1

You have to get the JSON value first and use it afterwards.
Run the statements below depending on the database codepage as is.

UTF-8 databases only

SELECT 
  XT.NAME
, XT.METHOD
--, JT.*
FROM 
(
VALUES XMLPARSE 
(
DOCUMENT '
<requestXML>
  <headers>
    <name>Accept</name>
    <value>text/plain, application/json, application/*+json, */*</value>
  </headers>
  <method>PUT</method>
  <payload>
    {
      "timestamp": "1659167441820"
    , "orderIdentifierCode": "OC22004795"
    , "clientName": "XXXX"
    , "country": "XX"
    , "vatNumber": "XXXXXXXX"
    , "orderDate": "XX/XX/XXXX"
    , "orderState": "XX"
    }
  </payload>
  <threadName>default task-xx</threadName>
  <url>http://localhost:8080/service_name</url>
</requestXML>
'
)
) X (T_RIC_XML)
CROSS JOIN XMLTABLE 
(
  '$XML/requestXML' PASSING X.T_RIC_XML AS "XML"
  COLUMNS 
    JV          CLOB (1K)       PATH 'payload'
  , NAME        VARCHAR (20)    PATH 'headers/name'
  , METHOD      VARCHAR (10)    PATH 'method'
) XT
/*
CROSS JOIN JSON_TABLE
(
  XT.JV, 'strict $' 
  COLUMNS
  (
    timestamp           VARCHAR(20)     PATH '$.timestamp'
  , orderIdentifierCode VARCHAR (20)    PATH '$.orderIdentifierCode'
  ) ERROR ON ERROR
) JT
WHERE JT.orderIdentifierCode = 'OC22004795'
*/
-- If you want to get other JSON columns
-- comment out the line below and uncomment the block above
WHERE JSON_VALUE (XT.JV, 'strict $.orderIdentifierCode' RETURNING VARCHAR (20)) = 'OC22004795'

All database encodings

You have to use older SYSTOOLS.JSON2BSON function in a non-unicode database.
The preferable way is not to use SYSTOOLS JSON functions. So, if you have UTF-8 database, it's better to use the above statement.
Seems, that SYSIBM.JSON_TABLE doesn't work in non-unicode databases.

SELECT 
  XT.NAME
, XT.METHOD
, JSON_VAL (SYSTOOLS.JSON2BSON (XT.JV), 'timestamp', 's:20')            AS timestamp
, JSON_VAL (SYSTOOLS.JSON2BSON (XT.JV), 'orderIdentifierCode', 's:20')  AS orderIdentifierCode
FROM 
(
VALUES XMLPARSE 
(
DOCUMENT '
<requestXML>
  <headers>
    <name>Accept</name>
    <value>text/plain, application/json, application/*+json, */*</value>
  </headers>
  <method>PUT</method>
  <payload>
    {
      "timestamp": "1659167441820"
    , "orderIdentifierCode": "OC22004795"
    , "clientName": "XXXX"
    , "country": "XX"
    , "vatNumber": "XXXXXXXX"
    , "orderDate": "XX/XX/XXXX"
    , "orderState": "XX"
    }
  </payload>
  <threadName>default task-xx</threadName>
  <url>http://localhost:8080/service_name</url>
</requestXML>
'
)
) X (T_RIC_XML)
CROSS JOIN XMLTABLE 
(
  '$XML/requestXML' PASSING X.T_RIC_XML AS "XML"
  COLUMNS 
    JV          CLOB (1K)       PATH 'payload'
  , NAME        VARCHAR (20)    PATH 'headers/name'
  , METHOD      VARCHAR (10)    PATH 'method'
) XT
WHERE JSON_VAL (SYSTOOLS.JSON2BSON (XT.JV), 'orderIdentifierCode', 's:20') = 'OC22004795'
Mark Barinstein
  • 11,456
  • 2
  • 8
  • 16
  • Hi, Mark. Thanks for the reply. Unfortunately the query didn't work. It seems there's a problem on the cross join: "XMLTABLE could not take such arguments. The schema is SYSIBM. The function name cannot be specified as a qualified name." Another question: is the "DOCUMENT" part needed? I need to extract my xml from this column "T_RIC_XML" of this table "EVDA.TETSIR_LOG_WS_PBE". Thanks again and sorry for my (maybe) dumb question. Not really skilled in SQL. – Ad1Os Aug 03 '22 at 13:21
  • @Ad1Os Check [this](https://dbfiddle.uk/?rdbms=db2_11.1&fiddle=40250f2ea4370fd48132d33e812ab4fa) link. What's your db2 platform and version? – Mark Barinstein Aug 03 '22 at 14:22
  • `XMLPARSE` (with the `DOCUMENT` clause) is needed to convert a string value to XML only. You don't need it, since your `T_RIC_XML` is already XML according to your example. Just use `EVDA.TETSIR_LOG_WS_PBE` instead of `(VALUES ...)` and remove `(T_RIC_XML)` after `X`. – Mark Barinstein Aug 04 '22 at 06:58
  • I suppose this is what you need: Driver: IBM Data Server Driver for JDBC and SQLJ (ver. 4.26.14, JDBC4.1) Effective version: IBM Db2 LUW (ver. 11.1.44) – Ad1Os Aug 04 '22 at 07:49
  • The following [link](https://dbfiddle.uk/?rdbms=db2_11.1&fiddle=5f84161ba334478d54bf2e9e2ab92466) uses exactly the same Db2 version as yours with a fully reproducible example: CREATE table, INSERT INTO it, and SELECT from it. You may post similar link with your example. – Mark Barinstein Aug 04 '22 at 08:22
  • thanks again. here the [link](https://dbfiddle.uk/?rdbms=db2_11.1&fiddle=237e0cee600afce6de5f11791e81f7ae) that you asked for. I wrote a similar `create table` as per my database. Unfortunately on Fiddle it works, but not on my SQL tool. There's another way WITHOUT using XMLTable? Anyway I really do appreciate your help. – Ad1Os Aug 05 '22 at 08:14
  • I found a solution, let me know what do you think about it: `SELECT * FROM ( SELECT XMLCAST(XMLQUERY('$XML//requestXML/payload' PASSING X.T_RIC_XML AS "XML") AS VARCHAR(8000)) as XML_TO_STRING FROM EVDA.TETSIR_LOG_WS_PBE X WHERE D_TMS_REG BETWEEN '2022-07-27 00:00:00.000001' AND '2022-08-02 23:59:59.999999' ) WHERE XML_TO_STRING like '%OC22006540%'; ` – Ad1Os Aug 05 '22 at 08:36
  • Your statement looks for a substring in a whole JSON document. The value you're searching for might be anywhere inside this document - in some another field or even in some field name. If you are OK with this - go ahead. But the correct way is as described in my answer. It's better to understand why it doesn't work in your "SQL tool". Isn't it better to change this tool to some normal one? – Mark Barinstein Aug 05 '22 at 08:58
  • I tried with DBeaver, Datagrip and so on. Cannot make it works properly, but I'll keep my eye on it for sure. – Ad1Os Aug 05 '22 at 09:02
  • Did I get you right that you run **exactly the same statements** as in my last link in your database and get some error? If yes, than it's very unlikely, that you use Db2 11.1.4 as you reported. What's the exact error message you get and on what exact statement? – Mark Barinstein Aug 05 '22 at 09:07
  • Here the full log: `[42815][-171] The statement was not processed because the data type, length or value of the argument for the parameter in position "1" of routine "SYSIBM.JSON_VALUE" is incorrect. Parameter name: "SYSIBM.JSON_VALUE".. SQLCODE=-171, SQLSTATE=42815, DRIVER=4.26.14 [56098][-727] An error occurred during implicit system action type "2". Information returned for the error includes SQLCODE "-171", SQLSTATE "42815" and message tokens "1|SYSIBM.JSON_VALUE".. SQLCODE=-727, SQLSTATE=56098, DRIVER=4.26.14` – Ad1Os Aug 05 '22 at 09:18
  • What's the result of the following queries? `SELECT SERVICE_LEVEL FROM SYSIBMADM.ENV_INST_INFO`, `SELECT VERSIONNUMBER FROM SYSIBM.SYSVERSIONS ORDER BY VERSION_TIMESTAMP DESC LIMIT 1`, `SELECT VALUE FROM SYSIBMADM.DBCFG WHERE NAME = 'codepage'`? – Mark Barinstein Aug 05 '22 at 10:22
  • SERVICE_LEVEL -> DB2 v11.1.4.4 SYSVERSION -> 11010404 VALUE -> 819 – Ad1Os Aug 05 '22 at 10:59
  • The problem is that you use non-unicode database. Look at the updated answer. – Mark Barinstein Aug 05 '22 at 11:31