Skip to Main Content
  • Questions
  • Unstable query results when adding json_value expressions

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Matthias.

Asked: August 15, 2023 - 5:38 pm UTC

Last updated: August 21, 2023 - 12:52 pm UTC

Version: 19.17.0.0.0

Viewed 1000+ times

You Asked

Hi,

I am trying to write a SQL-statement that uses json_value to extract and transform data from json.
An issue only appears when both
- a filter expression is used in the SQL-expression for more than one column (to access a specific element of an array)
- another column/expression is added, containing a json-path not targeting an array

It seems like all columns using the filter expression miracoulusly inherit the value of the very first column where a filter expression is used.

In the following example the values in column "id2" mirrors "id1". Remove the third column "someString" and "id2" suddenly gets correct data.

create table some_json (the_json clob constraint really_is_json check (the_json is json));
insert into some_json values (
'{
    "id": "a",
    "someString" : "some string",
    "externalId": [
        {
            "idType" : "1",
            "id" : "id of idType 1"
        },
        {
            "idType" : "2",
            "id" : "id of idType 2"
        }        
    ]
}'
);
insert into some_json values (
'{
    "id": "b",
    "someString" : "some string",
    "externalId": [
        {
            "idType" : "2",
            "id" : "another id of idType 2"
        },
        {
            "idType" : "1",
            "id" : "another id of idType 1"
        }
    ]
}'
);

select
    json_value(the_json, '$.someString') someString, --remove this line and it works fine
    json_value(the_json, '$.externalId[*]?(@.idType == "1").id') id1,
    json_value(the_json, '$.externalId[*]?(@.idType == "2").id') id2
from
    some_json;


Tested with Enterprise Edition 19.17.0.0.0 and 23c Free.

Am I using the filter operator wrong?



with LiveSQL Test Case:

and Chris said...

Yep, that's a bug.

I've raised it; I strongly recommend you raise this with support yourself too - this helps raise the priority of fixing it.

UPDATE - While you wait for a fix, you can disable transformation & get the correct result with this hint in 21c:

select /*+ NO_JSON_TABLE_TRANSFORM */
    json_value(the_json, '$.someString') someString, --remove this line and it works fine
    json_value(the_json, '$.externalId[*]?(@.idType == "1").id') id1,
    json_value(the_json, '$.externalId[*]?(@.idType == "2").id') id2
from
    some_json;

Rating

  (2 ratings)

We're not taking comments currently, so please try again later if you want to add a comment.

Comments

not in 19.17.0.0.0

Matthias, August 18, 2023 - 3:20 pm UTC

Thank you very much Chris but it seems the hint does nothing in version 19.17.0.0.0.
Chris Saxon
August 21, 2023 - 12:42 pm UTC

Ack; yes it seems it only works in 21c.

Workaround - use JSON_TABLE

mathguy, August 21, 2023 - 1:56 am UTC

When you use multiple calls to JSON_VALUE against the same JSON document in a query, the optimizer replaces them with a single call to JSON_TABLE, and it is supposed to do that correctly. Obviously you have uncovered a bug.

The hint Chris proposed is supposed to prevent this optimization - but the explain plan shows that the hint is ignored, it still performs a single JSONTABLE EVALUATION operation. Another bug, apparently.

Testing on 19.3 (my version), the following query has exactly the same explain plan as your query (showing a single JSONTABLE EVALUATION operation); but, unlike your query, the query below returns the correct output even when we include someString.

select somestring, id1, id2
from   some_json,
       json_table( the_json, '$'
                   columns( somestring path '$.someString',
                            id1 path '$.externalId[*]?(@.idType == "1").id',
                            id2 path '$.externalId[*]?(@.idType == "2").id'
                          )
                  )

Chris Saxon
August 21, 2023 - 12:52 pm UTC

I think the hint was added in 21; it's only referenced in the 23c documentation

More to Explore

SQL

The Oracle documentation contains a complete SQL reference.