I have an array of strings stored in oracle column as a json array in the following format:
["abc", "xyz"]
["cde", "fgh"]
["xyz"]
I have to write a query to check whether a given string is present in any of the arrays in any of the rows. In the above example I would like to see whether "xyz" is present. How should the json path be? I know I can use the 'like' clause but I don't think that is a neat way to do.
Why the query SELECT JSON_QUERY(my_column, '$[*]') FROM my_table is always returning null?
I did the following test, this may be what you are looking for:
create table t(json_v varchar2(40))
insert into t values('["abc", "xyz"]');
insert into t values('["cde", "fgh"]');
insert into t values('["xyz"]');
SELECT *
from t, json_table(t.json_v, '$[*]' columns (value PATH '$'))
WHERE value = 'xyz'
Output Result
JSON_V value
["abc", "xyz"] xyz
["xyz"] xyz
Your question two why the query always returns zero as you have to wrap the values see the JSON_QUERY syntax
SELECT JSON_QUERY(json_v, '$[*]' WITH WRAPPER) AS value FROM myTable;
Related
I'm writing a view were I transform a bunch of data to a more clean state to work with it, but I'm having some trouble with a coupe of fields that basically are json stuffed in columns. They're not large ones, and I've figured out with json_value how to get some of it, but the other column has an array within the json like this:
{"field1":"string","field2":0,"field3":[{"field1":"string","field2":true}]}
The data I need is the one in field3.
I've come up with a way of getting the portion of data I need raw (the contents of field3) and the idea is to extract then the data with json_vale
--code I figured out
select rtrim(ltrim(field3_raw,'['),']')
FROM json_table (
'{"field1":"string","field2":0,"field3":[{"field1":"string","field2":true}]}'format json,
'$'columns (field3_raw varchar2 format json path '$.field3')
)
;
which outputs
{"field1":"string","field2":true}
But the bad news comes when I change the raw json to the query like this:
Extract of the table I want to query:
|METADATA|
{"field1":"string1","field2":1,"field3":[{"field1":"string11","field2":true}]}
{"field1":"string2","field2":2,"field3":[{"field1":"string22","field2":true}]}
{"field1":"string3","field2":3,"field3":[{"field1":"string33","field2":true}]}
{"field1":"string4","field2":4,"field3":[{"field1":"string44","field2":true}]}
Query used:
select metadata_raw
FROM json_table (
(SELECT metadata FROM table)format json,
'$'columns (METADATA_RAW varchar2 format json path '$.field3')
)
;
Just to get this error:
SQL Error [1427] [21000]: ORA-01427: single-row subquery returns more than one row
Is there a way to retrieve in one query all the rows transformed the way I got it with json_table to use it as a subquery to build the column with the data I need in the view?
Additional details: Oracle 19c
As a little bit of background. I want to fill a column with jsonb values using values from other columns. Initially, I used this query:
UPDATE myTable
SET column_name =
row_to_json(rowset)
FROM (SELECT column1, column2 FROM myTable)rowset
However, this query seems to run for way too long (a few hours before I stopped it) on a dataset with 9 million records. So I looking for a solution with the second FROM clause and found the jsonb_insert function. To test the query I first ran this sample query:
SELECT jsonb_insert('{}','{column1}','500000')
Which gives {'column1':500000} as output. Perfect, so I tried to fill the value using the actual column:
SELECT jsonb_insert('{}':,'{column1}',column1) FROM myTable WHERE id = <test_id>
This gives a syntax error and a suggestion to add argument types, which leads me to the following:
SELECT jsonb_insert('{}':,'{column1}','column1')
FROM myTable WHERE id = <test_id>
SELECT jsonb_insert('{}'::jsonb,'{column1}'::jsonb,column1::numeric(8,0))
FROM myTable WHERE id = <test_id>
Both these queries give invalid input type syntax error, with Token 'column1' is invalid.
I really can not seem to find the correct syntax for these queries using documentation. Does anyone know what the correct syntax would be?
Because jsonb_insert function might need to use jsonb type for the new_value parameter
jsonb_insert(target jsonb, path text[], new_value jsonb [, insert_after boolean])
if we want to get number type of JSON, we can try to cast the column as string type before cast jsonb
if we want to get a string type of JSON, we can try to use concat function with double-quotes sign.
CREATE TABLE myTable (column1 varchar(50),column2 int);
INSERT INTO myTable VALUES('column1',50000);
SELECT jsonb_insert('{}','{column1}',concat('"',column1,'"')::jsonb) as JsonStringType,
jsonb_insert('{}','{column2}',coalesce(column2::TEXT,'null')::jsonb) as JsonNumberType
FROM myTable
sqlfiddle
Note
if our column value might be null we can try to put 'null' for coalesce function as coalesce(column2::TEXT,'null').
This question already has an answer here:
Why is JSON_QUERY sending back a null value?
(1 answer)
Closed last year.
I have the folowing Json data stored in a sql table :
{"OrderNumber":"12450-OF","OrderType":"OF"}
I need to extract the OrderNumber from a sql query
The folowing statement returns null:
select
JSON_QUERY(Metadata,'$.OrderNumber') AS 'orderNumber'
from Documents
where Documents is my table, and metadata is the column where my json data is stored.
You need to use JSON_VALUE() to extract a scalar value from a JSON content. JSON_QUERY() is usually used to extract an object or an array from a JSON string.
SELECT JSON_VALUE(Metadata,'$.OrderNumber') AS 'orderNumber'
FROM (VALUES
('{"OrderNumber":"12450-OF","OrderType":"OF"}')
) Documents (Metadata)
Note, that if you want to extract more values from the stored JSON, OPENJSON() with explicit schema is another option:
SELECT *
FROM Documents d
CROSS APPLY OPENJSON(d.Metadata, '$') WITH (
OrderNumber varchar(10) '$.OrderNumber',
OrderType varchar(2) '$.OrderType'
) j
You just need to replace function Json_Query to JSON_VALUE.
JSON_VALUE use for getting value from json.
JSON_Query use for getting object from json string.
For example, if you have:
"OrderNumber":["12450-OF","12450-02"]
then your query will return object
["12450-OF","12450-02"]
I have a Orable Table with one CLOB column which contains JSON data. I need a query which will search within the CLOB data.
I have used the condition where DBMS_LOB.instr(colName,'apple:')>0 which gives the records having apple:. However, I need to the query to return records with any number of apples other than blank, meaning, the json apple key should have a value.
I am thinking of something like where DBMS_LOB.instr(colName,'apple:**X**')>0, where X can be any number not null. I tried regexp_instr but it seems this is not correct for CLOB.
Are there any alternatives to solve this?
Generic string functions for parsing JSON inputs are dangerous - you will get false positives, for example, when something that looks like a JSON object is in fact embedded in a string value. (Illustrated by ID = 101 in my example below.)
The ideal scenario is that you are using Oracle 19 or higher; in that case you can use a simple call to json_exists as illustrated below. In the sample table I create, the first JSON string does not contain a member named apple. In the second row, the string does contain a member apple but the value is null. The first query I show (looking for all JSON with an apple member) will include this row in the output. The last query is what you need: it adds a filter so that a JSON string must include at least one apple member with non-null value (regardless of whether it also includes other members named apple, possibly with null value).
create table sample_data
( id number primary key
, colname clob check (colname is json)
);
insert into sample_data
values (101, '{name:"Chen", age:83, values:["{apple:6}", "street"]}');
insert into sample_data
values (102, '{data: {fruits: [{orange:33}, {apple:null}, {plum:44}]}}');
insert into sample_data
values (103, '[{po:3, "prods":[{"apple":4}, {"banana":null}]},
{po:4, "prods":null}]');
Note that I intentionally mixed together quoted and unquoted member names, to verify that the queries below work correctly in all cases. (Remember also that member names in JSON are case sensitive, even in Oracle!)
select id
from sample_data
where json_exists(colname, '$..apple')
;
ID
---
102
103
This is the query you need. Notice the .. in the path (meaning - find an object member named apple anywhere in the JSON) and the filter at the end.
select id
from sample_data
where json_exists(colname, '$..apple?(# != null)')
;
ID
---
103
You can use regexp_like function for this:
where regexp_like(colName,'apple : [0-9]')
I have a table called table with column called column with datatype text with values like '["1","2"]'.
I need to get all records which has "1" as one of the element.
select *
from table
where column.....?
How should the where clause be?
Simply use LIKE. Keep the double quotes to pass 1, but avoid other numbers containing that digit.
select *
from table
where column like '%"1"%'
I think you can use ? operator on jsonb type:
select *
from (
select '["1","2"]' union all
select '["0"]'
) as a(data)
where
a.data::jsonb ? '1'
In general, I'd consider storing your data as jsonb instead of string.
db<>fiddle example