MariaDB COLUMN_JSON query returns binary - json

I've been trying to use dynamic columns with an instance of MariaDB v10.1.12.
First, I send the following query:
INSERT INTO savedDisplays (user, name, body, dataSource, params) VALUES ('Marty', 'Hey', 'Hoy', 'temp', COLUMN_CREATE('type', 'tab', 'col0', 'champions', 'col1', 'averageResults'));
Where params' type was defined as a blob, just like the documentation suggests.
The query is accepted, the table updated. If I COLUMN_CHECK the results, it tells me it's fine.
But when I try to select:
"SELECT COLUMN_JSON(params) AS params FROM savedDisplays;
I get a {type: "Buffer", data: Array} containing binary returned to me, instead of the {"type":"tab", "col0":"champions", "col1":"averageResults"} I expect.
EDIT: I can use COLUMN_GET just fine, but I need every column inside the params field, and I need to check the type property first to know what kind of and how many columns there are in the JSON / params field. I could probably make it work still, but that would require multiple queries, as opposed to only one.
Any ideas?

Try:
SELECT CONVERT(COLUMN_JSON(params) USING utf8) AS params FROM savedDisplays
In MariaDB 10 this works at every table:
SELECT CONVERT(COLUMN_JSON(COLUMN_CREATE('t', text, 'v', value)) USING utf8)
as json FROM test WHERE 1 AND value LIKE '%12345%' LIMIT 10;
output in node.js
[ TextRow { json: '{"t":"test text","v":"0.5339044212345805"}' } ]

Related

Pull data from JSON column and create new output with ABSENT ON NULL option

I have a JSON column in an Oracle DB where it was populated without the ABSENT ON NULL option and there are some pretty long lengths because of this.
I would like to trim things down and have created a new table similar to the first but I would like to select the JSON from form the old, add the ABSENT ON NULL option and place the new values in reducing the column length.
So I can see the JSON easy enough like
SELECT json_query(json_data,'$') FROM table;
This will give a result like:
{
"REC_TYPE_IND":"1",
"ID":"1234",
"OTHER_ID":"4321",
"LOCATION":null,
"EFF_BEG_DT":"19970101",
"EFF_END_DT":"99991231",
"NAME":"Joe",
"CITY":null
}
When I try to remove the null values like
SELECT json_object (json_query(json_data,'$') ABSENT ON NULL
RETURNING VARCHAR2(4000)
) AS col1 FROM table;
I get the following:
ORA-02000: missing VALUE keyword
I assume this is because the funcion json_object is expecting the format:
json_object ('REC_TYPE_IND' VALUE '1',
'ID' VALUE '1234')
Is there a way around this, to turn the JSON back into values that JSON_OBJECT can recognize like above or is there a function I am missing?

mysql query works in phpmyadmin but not in node.js

I have a query like this...
SELECT *
FROM `000027`,`000028`
WHERE `000027`.id=(SELECT max(`000027`.id) FROM `000027`)
AND `000028`.id=(SELECT max(`000028`.id) FROM `000028`)
which returns something like this in phpmyadmin...
id time value id time value
However, in react.js it is only returning one of these like this...
id time value
2 questions, Why is it doing this? and, how can I get it to return both instead of one?
my node.js code...
const sqlSelect = "SELECT * FROM `000027`,`000028` WHERE `000027`.id=(SELECT max(`000027`.id) FROM `000027`) AND `000028`.id=(SELECT max(`000028`.id) FROM `000028`)"
dbPlant.query(sqlSelect, (err, result) => {
console.log(result)
res.send(result)
res.end()
})
and it sends this back with only one rowdatapacket when it should be two, or two of each of those values...
[
RowDataPacket {
id: 652,
time: 2021-01-24T17:28:01.000Z,
value: '262'
}
]
Your two tables have some column names in common. This is okay to have repeated column names in a result set in the mysql client, but some programming interfaces map a rows of a result set into a hash array, where the column names are the keys. So if you have duplicate column names, one naturally overwrites the other.
The remedy is to define column aliases for one or the other of each duplicate, so they are mapped into distinct keys in the result set.
You must do this one column at a time. Sorry, you can't use SELECT * anymore (you shouldn't use SELECT * anyway). There is no "automatic alias all columns" option.
SELECT
`000027`.id AS id27,
`000027`.time AS time27,
`000027`.value AS value27,
`000028`.id AS id28,
`000028`.time AS time28,
`000028`.value AS value28
FROM `000027`,`000028`
WHERE `000027`.id=(SELECT max(`000027`.id) FROM `000027`)
AND `000028`.id=(SELECT max(`000028`.id) FROM `000028`)

Unpacking JSON Into Flat Format

I have JSON that resembles the following:
{
"ANNOTATIONS": [
{
"Label": "CommingledProduct",
"Text": "NBP"
},
{
"Label": "CommingledVenue",
"Text": "OTC"
}
]
}
I need to unpack this into a flat table with columns matching the annotation labels. So columns based on the above json become:
comingled_product
comingled_venue
The JSON is coming from a json field in a source table and being unpacked into another table.
I know that I could code as follows:
INSERT INTO my_target_table (comingled_product, comingled_venue)
SELECT
payload->'ANNOTATIONS'->0->>'Text',
payload->'ANNOTATIONS'->1->>'Text'
FROM my_source_table;
However, I would rather not use the ordinals of the annotations. I would prefer to use some syntax mirroring the psuedo-code below:
INSERT INTO my_target_table (comingled_product, comingled_venue)
SELECT
payload->'ANNOTATIONS'->'label="ComingledProduct"'->>'Text',
payload->'ANNOTATIONS'->'label="ComingledVenueID"'->>'Text'
FROM my_source_table;
Can anyone tell me if what I'm trying to ahcieve is possible and how to do it? There are more than the two annotations I have included in the sample, so anything that involves multiple joins is probably a no go.
Using PostGres 10.7
demo:db<>fiddle
WITH cte AS (
SELECT
elems.value
FROM
my_source_table,
json_array_elements(payload -> 'ANNOTATIONS') elems
)
SELECT
(SELECT value ->> 'Text' FROM cte WHERE value ->> 'Label' = 'CommingledProduct'),
(SELECT value ->> 'Text' FROM cte WHERE value ->> 'Label' = 'CommingledVenue')
Expanding the array into one row per array element and store this result for further usage into a CTE
This result can be used to query the expected values (without doing the expanding twice)
Could be a little bit faster:
demo:db<>fiddle
SELECT
payload,
MIN(the_text) FILTER (WHERE label = 'CommingledProduct'),
MIN(the_text) FILTER (WHERE label = 'CommingledVenue')
FROM (
SELECT
payload::text AS payload,
elems ->> 'Label' AS label,
elems ->> 'Text' AS the_text
FROM
my_source_table,
json_array_elements(payload -> 'ANNOTATIONS') elems
) s
GROUP BY payload
The answer from #S-Man is great and you should use that for your postgres 10.7. json_path will be added in postgres 12, which will allow you to do something a little bit closer to your pseudo-code, but only with jsonb (not json):
INSERT INTO my_target_table (comingled_product, comingled_venue)
SELECT jsonb_path_query(payload,
'$.ANNOTATIONS[*] ? (#.Label == "CommingledProduct")')->>'Text',
jsonb_path_query(payload,
'$.ANNOTATIONS[*] ? (#.Label == "CommingledVenue")')->>'Text'
FROM my_source_table;
The jsonb_path_query syntax takes a bit to figure out, but it is basically returning elements of the ANNOTATIONS array for which the Label equals either CommingledProduct or CommingledVenue. jsonb_path_query returns a jsonb object, so we can use the ->> operator to grab the value of 'Text' from the object.

MySql - Select some characters after certain word and add it to another column

I have table which include 2 column: title and param, the values are like the following:
-title: Teaching
-params:
{"ufield926":"34","ufield927":"Sud","ufield928":"Ara","ufield929":"Mecca",
"ufield930":"1\/1\/1983","ufield933":"011","ufield934":"Mub",
"ufield943":"SU\/HI\/14","ufield944":"Average","ufield946":"Female"}
I want to extract the code after "ufield943": which is SU\/HI\/14 only and concatenate it with the value in title column to be like the following:
Teaching (SU\/HI\/14)
Try this query:
select *,
substring(
params,
locate('ufield943', params) + 12,
locate('ufield944', params) - locate('ufield943', params) - 15
)
from tbl;
But I assumed that ufield944 occurs directly after ufield943.
Demo
The value in params is JSON, so your best solution might be to look at MySQL JSON support.
I'm not familiar with MySQL JSON support, if that doesn't work for you I would look at MySQL's REGEXP_SUBSTR and REGEXP_REPLACE to do this:
SELECT
title
REGEXP_REPLACE(
REGEXP_SUBSTR(params, '"ufield943"[[:space:]]*:[[:space:]]*"([^"\\]|\\.)+'),
'^"ufield943"[[:space:]]*:[[:space:]]*"', '')
FROM MyTable
The regex finds the value regardless of where it is in the json and allows for whitespace in the column (like "ufield943" : "SU\/HI\/14").

JSON_REMOVE object in MySQL

I am trying to delete objects from my JSON array in MySQL.
I have a table called cart with two fields quote_id type int and items type json with the following row stored inside MySQL
quote_id: 0
items:
[
{
"a":42,
"b":"test4"
},
{
"a":32,
"b":"test3"
}
]
I am trying to create a query which would delete json objects from the json array. For example every
{
"a":32,
"b":"test3"
}
I have tried many queries. First I ended up with this:
UPDATE cart
SET items = IFNULL(JSON_REMOVE(items, JSON_UNQUOTE(JSON_SEARCH(items, 'one', 'test3'))), items)
WHERE quote_id = 13392;
However it just deletes "b":"test3" from the second object and left the "a":32 in it and I need a query that would find the whole object and would delete it.
This is my second query:
UPDATE cart
SET items = IFNULL(JSON_REMOVE(items, JSON_SEARCH(items, 'one', CAST('{"a": 32, "b": "test3"}' AS JSON))), items)
WHERE quote_id = 13392;
However I don't think the search on it works. I tried it without using the CAST()AS JSON, however it still did not work.
As I said I am pretty sure the problem is with the JSON_SEARCH, but maybe someone has the solution?
Thank you!
The JSON_SEARCH returns the path of the property, not the path to the object itself.
So you can use the following solution to get the object path with SUBSTR:
SELECT JSON_REMOVE(items,
SUBSTR(JSON_UNQUOTE(JSON_SEARCH(items, 'one', 'test3')), 1, LOCATE('.', JSON_UNQUOTE(JSON_SEARCH(items, 'one', 'test3')))-1)
) FROM cart
You can also use REGEXP_SUBSTR to get the object path:
SELECT JSON_REMOVE(items, REGEXP_SUBSTR(JSON_UNQUOTE(JSON_SEARCH(items, 'one', 'test3')), '^\\$\\[[0-9]+\\]'))
FROM cart
demo on dbfiddle.uk