Fetching nested JSON data in HBase using Apache Drill - json

I am using Apache Drill to run SQL queries on a HBase table. The value in one of the columns is:
0: jdbc:drill:schema:hbase:zk=localhost> select cast(address['street'] as varchar(20)) from hbase.students;
+------------+
| EXPR$0 |
+------------+
| {"id": 123} |
+------------+
1 row selected (0.507 seconds)
I would like to access the id field using a query. Something like:
0: jdbc:drill:schema:hbase:zk=localhost> select tbl.address['street']['id'] from hbase.students as tbl;
+------------+
| EXPR$0 |
+------------+
| null |
+------------+
As you can see, this does not work. I am run to similar queries on JSON data in a file. My question is can I query JSON data in HBase.

OK. I found the answer to this question, in case someone else has the same requirement.
The first step is to convert the HBase data to JSON using the built-in convert_from() function. A view can be created against which the queries can be run.
> create or replace view Street as select convert_from(Students.address.street, 'JSON') json from hbase.Customer;
Then, run query against the view
> select * from Street;
> select Street.json.id from Street;

You can also use a subquery to convert the data in your HBase column into JSON:
select t.json.id
from (select convert_from(Students.address.street, 'JSON') json
from hbase.Customer) t;

Related

How to convert a string value of json into dateTime and compare

SELECT JSON_EXTRACT(z2schedule,'$[*].start') as startDate from
cpmdev_z2weekly_schedule
After running above code I am getting response as :-
Now If I tried to compare each value to time value using below code but it is not working:-
SELECT JSON_EXTRACT(z2schedule,'$[*].start') as startDate from
cpmdev_z2weekly_schedule where
JSON_EXTRACT(z2schedule,CONVERT('$[*].start'),'TIME')>
'CONVERT('2022-11-02 13:10:00:000', TIME)
My requirement is only to compare each value with the time value and return only if the value is greater than given time.
For Example in Table I have Data as:-
[{"start":"09:00:00.000","end":"17:00:00.000"}]
[{"start":"10:00:00.000","end":"17:00:00.000"}]
[{"start":"11:00:00.000","end":"17:00:00.000"}]
Now I want all the start Date which is greater then 10:00:00
In above case then it should return :
11:00:00.000
The JSON you show is an array of objects. When you use $[*].start, it returns a JSON array. This is not a single time. You can see the square brackets around the time value:
mysql> set #j = '[{"start":"09:00:00.000","end":"17:00:00.000"}]';
mysql> select json_extract(#j, '$[*].start') as times;
+------------------+
| times |
+------------------+
| ["09:00:00.000"] |
+------------------+
The square brackets make it not valid as a time value.
mysql> select convert(json_extract(#j, '$[*].start'), time) as times;
+-------+
| times |
+-------+
| NULL |
+-------+
Since your JSON array seems to have only one object in it, you could use $[0] to select the first object in the array. Then it returns a single string value and that is convertable to a time:
mysql> select convert(json_extract(#j, '$[0].start'), time) as time;
+----------+
| time |
+----------+
| 09:00:00 |
+----------+
Note also that the data type named in the CONVERT() function is a keyword, not a quoted string. That is, 'time' is incorrect, just use time.
If your JSON array may have more than one object, and you need to test all of them, then you should use the JSON_TABLE() function.
By the way, all these issues would be avoided if you stored your start and end times in normal rows and columns. Using JSON makes many queries more difficult to develop and optimize. You should consider normalizing your data, and not using JSON.

How to regexp in MySql json string

Let's assume this users table:
-----------------------------------------
| id | ... | info |
-----------------------------------------
| 1 | ... | {"items":["132","136"]} |
I need to make a request to fetch users that have items with id == 136.
This following is the sql I built but it does not work and I dont understand why:
SELECT _u.id FROM users _u WHERE _u.info REGEXP '("items":)([)("136")(])'
Thank you in advance!
Here is one approach using the MySQL JSON functions:
SELECT *
FROM yourTable
WHERE JSON_SEARCH(JSON_EXTRACT(json, "$.items"), 'one', "136") IS NOT NULL;
Demo
The call to JSON_EXTRACT first extracts the JSON array under the items key. Then, we use JSON_SEARCH to try to find an element "136".
Edit:
If you are certain that the JSON to be searched would always just be one key items along with a single level JSON array, then REGEXP might be viable here:
SELECT *
FROM yourTable
WHERE json REGEXP '"items":\\[.*"136".*\\]';
Demo

How can I convert the string values inside a MySQL JSON array to upper case?

I have a table that contains a JSON column, and in it a JSON array:
mysql> SELECT profile->'$.countriesVisited' from users;
+-------------------------------+
| profile->'$.countriesVisited' |
+-------------------------------+
| ["us", "il"] |
| ["co", "ph"] |
+-------------------------------+
2 rows in set (0.00 sec)
I want to convert the values inside the array into upper case. (I am assuming this answer would also assist lower case, string replacements.. etc.)
I've been trying to use UPPER, JSON_ARRAY, JSON_QUOTE, JSON_UNQUOTE, etc - at best I end up with a string representation of what I want.
How can I do this? I'm running MySQL 5.7.19.
You need to use JSON casting. Try the following:
UPDATE users
SET profile = JSON_SET(
profile,
'$.countriesVisited',
CAST(
UPPER(profile->'$.countriesVisited')
AS JSON
)
);

MySQL JSON extract values only if there value > 1

I have the following table:
+-------------+----------------+
| id | server |
+-------------+----------------+
| 1 | ["1", "15"] |
+-------------+----------------+
I need to get only value that is grather that 1 so in above example i need to get from output only 15
I try using this:
SELECT
JSON_EXTRACT(server, "$[*]") as server
FROM streams
WHERE JSON_EXTRACT(server, "$[*]") != JSON_QUOTE('1')
AND id=1;
But i always get ["1", "15"] and need to get ["15"].
Unfortunately, you can't do this with MySQL's JSON_EXTRACT and JSON_SEARCH functions as they perform extraction and exact matching (not comparison) respectively. So, you have two options:
Normalise the table and have server values into a new column (recommended)
Fetch all the values and perform the filtering in service layer
I added this:
SELECT CASE WHEN
JSON_UNQUOTE(JSON_SEARCH(server, 'all', 1)) IS NULL THEN
JSON_REMOVE(server, '$."1"')
ELSE
JSON_REMOVE(server, JSON_UNQUOTE(JSON_SEARCH(server, 'one', 1)))
END AS server
FROM streams WHERE id=2 AND server NOT LIKE '%[]%';
Now it works but if ["1"] is only 1 in json column i get []...a added NOT LIKE '%[]%' but it prints out always []...where i need to add to get no results found from mysql?

Select a particular value of JSON string using MySQL

I have a table that looks like this
+------+------------------------------------+
| id | details |
+------+------------------------------------+
| 1 | {"price":"24.99","currency":"USD"} |
+------+------------------------------------+
Is it possible to, with a single MySQL select statement, obtain the value of price 24.99?
Yes, you can using JSON_EXTRACT
It probably should be like:
SELECT JSON_EXTRACT(details, "$.price")
FROM table_name
or another form:
SELECT details->"$.price"
FROM table_name
(I don't have MySql to test it)
Note that the price in your JSON stored as a string, not a number and you probably would want to cast it to a DECIMAL.