MariaDb: JSON_ARRAY_APPEND to empty array - sql

I find it confusing (and not working) to use JSON_ARRAY_APPEND with empty JSON arrays according to the docs. I'm using newest version of MariaDb 10.2.6.
When I do:
SELECT JSON_ARRAY_APPEND('[1]', '$', JSON_EXTRACT('{"test":123}', '$'));
Result is as expected:
[1, {"test": 123}]
(the same with:
SELECT JSON_ARRAY_APPEND(JSON_EXTRACT('[1]', '$'), '$', JSON_EXTRACT('{"test":123}', '$'));
)
But, when I operate on empty array:
SELECT JSON_ARRAY_APPEND('[]', '$', JSON_EXTRACT('{"test":123}', '$'));
The result is:
(NULL)
Probably because of this I cannot update field with empty array. When I do:
UPDATE `test` SET `test`.`log` = JSON_ARRAY_APPEND(`test`.`log`, '$', JSON_EXTRACT('{"test":123}', '$'))
I get an error:
(4038) Syntax error in JSON text in argument 1 to function 'json_array_append' at position 2
Am I getting something wrong or is it some kind of bug or caveat?
Regards,
JK.

MariaDB [test]> SELECT JSON_ARRAY_APPEND(JSON_ARRAY(''), '$', JSON_EXTRACT('{"test":123}', '$'))\G
*************************** 1. row ***************************
JSON_ARRAY_APPEND(JSON_ARRAY(''), '$', JSON_EXTRACT('{"test":123}', '$')): ["", {"test": 123}]
1 row in set (0.00 sec)

Related

How to add a key value pair in Json type column in Postgres

I have a json type column(Status) in Postgres database(9.4.9). I want to add new key value pair for existing value of status. Example:
Existing Status:
"status": {
"keysterStatus": "In Progress"
}
After Adding Key value pair i want it to look like this
"status": {
"provisioningStatus": "In Progress",
"keysterStatus": "In Progress"
}
I have been using repository save() method as of now to get this done but that is writing whole row and there is chance of concurrent read and write in case of multiple request. So wanted to get rid of save() method and go with column level update.
First of all PG9.4 is obsolette and even unsopperted now. PG9.5 contains as json_set function:
SELECT jsonb_set(status::jsonb,
'{provisioningStatus}',
to_jsonb('In Progress'))::jsonb
FROM ....;
as possibility to use concatenation || swith converting to jsonb and than back:
SELECT (status::jsonb || '{"provisioningStatus": "In Progress"}')::json
FROM ....;
For PG9.4,if you know schema for json, uou can use json_populate_record/row_to_json :
SELECT (
SELECT row_to_json(r)
FROM (
SELECT r.*, 'In Progress' AS provisioningStatus
FROM json_populate_record(null::myrowtype, status) AS r
) AS r
) AS result
FROM ....
Or you can use json_each_text:
SELECT (
SELECT json_object_agg(key, value)
FROM (
SELECT *
FROM json_each_text(status)
UNION ALL
SELECT 'provisioningStatus', 'In Progress'
) AS a
) AS result
FROM ...
And probably the last (but ugly) method is just convert json to string, remove last '}', add "provisioningStatus": "In Progress"}' and convert back to json:
SELECT (substr(status::text, 1, length(status::text) - 1)
|| ', "provisioningStatus": "In Progress"}')::json
FROM ...
UPDATE table_name SET column_name = jsonb_set(cast(column_name as jsonb), '{key}', '"value"', true) WHERE id = 'target_id';
This will add the key value pair in the json column if it doesn't exist already, if the key exist it will override the value of it.

Coalesce array of integers in Hive

foo_ids is an array of type bigint, but the entire array could be null. If the array is null, I want an empty array instead.
If I do this: COALESCE(foo_ids, ARRAY())
I get:
FAILED: SemanticException [Error 10016]: Line 13:45 Argument type mismatch 'ARRAY': The expressions after COALESCE should all have the same type: "array<bigint>" is expected but "array<string>" is found
If I do this: COALESCE(foo_ids, ARRAY<BIGINT>())
I get a syntax error: FAILED: ParseException line 13:59 cannot recognize input near ')' ')' 'AS' in expression specification
What's the proper syntax here?
Use this one:
coalesce(foo_ids, array(cast(null as bigint)))
Before, hive is treating empty array [] as []. But in Hadoop2, hive is now showing empty array [] as null (see refence below). Use array(cast(null as bigint)) for empty array of type bigint. Strangely, the size of empty array is -1 (instead of 0). Hope this helps. Thanks.
Sample data:
foo_ids
[112345677899098765,1123456778990987633]
[null,null]
NULL
select foo_ids, size(foo_ids) as sz from tbl;
Result:
foo_ids sz
[112345677899098765,1123456778990987633] 2
[null,null] 2
NULL -1
select foo_ids, coalesce(foo_ids, array(cast(null as bigint))) as newfoo from tbl;
Result:
foo_ids newfoo
[112345677899098765,1123456778990987633] [112345677899098765,1123456778990987633]
[null,null] [null,null]
NULL NULL
Reference: https://docs.treasuredata.com/articles/hive-change-201602

postgresql, jsonb field, array append via jsonb_set and jsonb_array_length

I have postgresql with jsonb field that always contains array.
I need to append new values to that array or update already existing values by index.
Looks like jsonb_set function meet my requirements. And for append new element i just need to max array index and update element with it.
But i have a trouble doing this. Lets make it step by step.
We have table campaigns with jsonb field team_members.
select id, jsonb_set(team_members, '{0}', '{"name" : "123"}') from campaigns;
id | jsonb_set
-----+-------------------
102 | [{"name": "123"}]
Okay great, if set path '{0}' statically everything works.
Lets do that dynamically
SQL for getting array length (it is our index for append)
select '{' || jsonb_array_length(team_members) || '}'::text from campaigns;
?column?
----------
{0}
Getting all together
select jsonb_set(team_members, '{' || jsonb_array_length(team_members) || '}', '{"name" : "123"}') from campaigns;
ERROR: function jsonb_set(jsonb, text, unknown) does not exist
LINE 1: select jsonb_set(team_members, '{' ||
jsonb_array_length(tea...
^ HINT: No function matches the given name and argument types. You might
need to add explicit type casts.
My question is - how can i get rid of this error ? What i'm doing wrong ?
Thanks in advance.
something like this?..
t=# with jpath as (select concat('{',0,'}')::text[] path) select jsonb_set('[]'::jsonb,path,'{"name": "123"}'::jsonb) from jpath;
jsonb_set
-------------------
[{"name": "123"}]
(1 row)
In your case should be like:
select
jsonb_set(
team_members
, concat('{',jsonb_array_length(team_members),'}')::text[]
, '{"name" : "123"}'
)
from campaigns;

ST_DIFFERENCE returning GeometryCollection instead of MultiPoint

I'm trying to get the difference between two multipoints. I am doing this using the query location = ST_Difference(location, other_geo). This works when the result is not empty, however, if the two multipoints are exactly the same, the resulting object is a GeometryCollection instead of an empty MultiPoint, as would be returned from ST_geomFromText('MULTIPOINT EMPTY'). How do I get the result to be an empty multipoint object?
The following query results in a multipoint:
SELECT ST_asGeoJSON(ST_Difference(ST_geomFromText('MultiPoint(1 2, 3 4)', 4326), ST_geomFromText('MultiPoint(1 2)', 4326)));
Result: {"type":"Point","coordinates":[3,4]}
This one results in an empty GeometryCollection:
SELECT ST_asGeoJSON(ST_Difference(ST_geomFromText('MultiPoint(1 2)', 4326), ST_geomFromText('MultiPoint(1 2)', 4326)));
Result: {"type":"GeometryCollection","geometries":[]}
Try using ST_Multi and ST_CollectionExtract to always return a MultiPoint geometry with zero or more points:
SELECT ST_AsGeoJSON(ST_Multi(ST_CollectionExtract(ST_Difference(a, b), 1)))
FROM (
SELECT 'MultiPoint(1 2, 3 4)'::geometry a, 'MultiPoint(1 2)'::geometry b
UNION SELECT 'MultiPoint(1 2)', 'MultiPoint(1 2)'
) data;
st_asgeojson
---------------------------------------------
{"type":"MultiPoint","coordinates":[]}
{"type":"MultiPoint","coordinates":[[3,4]]}
(2 rows)

Postgresql regexp_replace 'g' flag

i have string
[[good|12345]] [[bad1 [[bad2 [[bad3 [[bad4 [[bad5 [[good|12345]]
i need to kill [[ if word havent | after it.
what i do:
select regexp_replace('[[good|12345]] [[bad1 [[bad2 [[bad3 [[bad4 [[bad5 [[good|12345]]',
'\[\[([^\|]+?(\[\[|\Z))', '\1', 'g')
what i get:
[[good|12345]] bad1 [[bad2 bad3 [[bad4 bad5 [[good|12345]]
what i want to get:
[[good|12345]] bad1 bad2 bad3 bad4 bad5 [[good|12345]]
it looks like the last 2 symbols of my regexp [[ doesn't exists in next iteration of regexp
You should use a look-ahead instead of a group:
select regexp_replace('[[good|12345]] [[bad1 [[bad2 [[bad3 [[bad4 [[bad5 [[good|12345]]', '\[\[([^\|]+?(?=\[\[|\Z))', '\1', 'g')
See demo SQL fiddle
The (?=\[\[|\Z) look-ahead only checks the presence of [[, but does not consume the characters (i.e. matches and moves on through the string). Thus, the following [[ remain available for the next match.