How to normalize column values in new column? - mysql

I've below data in table, val1,val2,val3 are of double type. x represents record is having old value and y represents new value. So we need to concatenate all double values in respective col (oldVal,newVal) based on x and y value
ID,region,status,val1,val2,val3
1, aa, x, 10, 11, 13
1, aa, y, 12, 14, 15
2, bb, x, null, null, null
2, bb, y, null, null, null
expected output, oldVal,newVal are of varchar type
ID,region,oldVal,newVal
1, aa,10-11-13, 12-14-15
1, bb,null, null
how to de-normalize can be done for this to get expected output ?
Note: If any of the value is null out of (val1, val2, val3), then null value should not be considered.
1,2,null > 1-2

You can try to use the condition aggregate function with CONCAT_WS function.
SELECT ID,
region,
MAX(CASE WHEN status = 'x' THEN CONCAT_WS('-',val1,val2,val3) END) oldVal,
MAX(CASE WHEN status = 'y' THEN CONCAT_WS('-',val1,val2,val3) END) newVal
FROM T
GROUP BY ID,region
sqlfiddle

Related

How to split column values by comma and return it as an array

As you can see below I have Name column. I want to split it by / and return the value in array.
MyTable
Id
Name
1
John/Warner/Jacob
2
Kol
If I write a query as
Select Id, Name from MyTable
it will return
{
"id": 1,
"name": "John/Warner/Jacob",
},
{
"id": 2,
"name": "Kol",
},
Which query should I write to get below result ?
{
"id": 1,
"name": ["John", "Warner", "Jacob"],
},
{
"id": 2,
"name": ["Kol"] ,
},
Don't think you can return an array in the query itself, but you could do this...
SELECT id,
SUBSTRING_INDEX(name, '/', 1)
AS name_part_1,
SUBSTRING_INDEX(name, '/', -1)
AS name_part_2
FROM tableName;
Only way to build it as an array would be when processing the result accordingly in whatever language you are using.
You can define a function split, which is based on the fact that substring_index(substring_index(name,'/',x),'/',-1) will return the x-th part of a name when separated by '/'.
CREATE FUNCTION `test`.`SPLIT`(s varchar(200), c char, i integer) RETURNS varchar(200) CHARSET utf8mb4
DETERMINISTIC
BEGIN
DECLARE retval varchar(200);
WITH RECURSIVE split as (
select 1 as x,substring_index(substring_index(s,c,1),c,-1) as y, s
union all
select x+1,substring_index(substring_index(s,c,x+1),c,-1),s from split where x<= (LENGTH(s) - LENGTH(REPLACE(s,c,'')))
)
SELECT y INTO retval FROM split WHERE x=i ;
return retval;
END
and then do:
with mytable as (
select 1 as Id, 'John/Warner/Jacob' as Name
union all
select 2, 'Kol')
select
id, split(Name,'/',x) as name
from mytable
cross join (select 1 as x union all select 2 union all select 3) x
order by id, name;
output:
Id
name
1
Jacob
1
John
1
Warner
2
[NULL]
2
[NULL]
2
Kol
It is, of course, possible to refine this, and leave out the NULL values ...
I will not convert this output to JSON for you ...

Mysql Data truncated for column error when modify a column definition

I have a table with the following column definition
`numericValue1` double GENERATED ALWAYS AS ((case when (json_type(json_extract(`object`,'$.numericValue1')) = 'NULL')) then NULL else json_unquote(json_extract(`object`,'$.numericValue1')) end)) VIRTUAL;
Now I am trying to run the following script to change the column definition
ALTER TABLE `MyTable`
MODIFY `numericValue1` double GENERATED ALWAYS AS ((case when (json_type(json_extract(`object`,'$.numericValue1')) = 'NULL') OR (json_type(json_extract(`object`,'$.numericValue1')) = 'STRING') then NULL else json_unquote(json_extract(`object`,'$.numericValue1')) end)) VIRTUAL;
I then get an error
Data truncated for column 'numericValue1' at row 2
Any ideas? How can I by pass this error?
CREATE TABLE `MyTable`(
`object` JSON,
`numericValue1` double GENERATED ALWAYS AS (case when (json_type(json_extract(`object`,'$.numericValue1')) = 'NULL')
then NULL
else json_unquote(json_extract(`object`,'$.numericValue1'))
end) VIRTUAL
);
INSERT INTO `MyTable` (`object`) VALUES
('{"id":1,"numericValue1":123.456}'),
('{"id":2,"numericValue1":null}');
INSERT INTO `MyTable` (`object`) VALUES
('{"id":1,"numericValue1":"asdf"}');
Data truncated for column 'numericValue1' at row 1
SELECT * FROM `MyTable`;
object | numericValue1
:---------------------------------- | ------------:
{"id": 1, "numericValue1": 123.456} | 123.456
{"id": 2, "numericValue1": null} | null
ALTER TABLE `MyTable`
MODIFY `numericValue1` double GENERATED ALWAYS AS ((case when (json_type(json_extract(`object`,'$.numericValue1')) = 'NULL') OR (json_type(json_extract(`object`,'$.numericValue1')) = 'STRING')
then NULL
else json_unquote(json_extract(`object`,'$.numericValue1'))
end)) VIRTUAL;
INSERT INTO `MyTable` (`object`) VALUES
('{"id":1,"numericValue1":"asdf"}');
SELECT * FROM `MyTable`;
object | numericValue1
:---------------------------------- | ------------:
{"id": 1, "numericValue1": 123.456} | 123.456
{"id": 2, "numericValue1": null} | null
{"id": 1, "numericValue1": "asdf"} | null
db<>fiddle here
As you can see only when generated value does not match the datatype then shown error message is produced.

MySQL JSON: finding value of sibling element in sub-array

I have the following (pseudo)JSON in a type JSON (LONGTEXT) column in my MariaDB 10.2
{"order":
{"otherstuff":...},
{"dates":
[
{
"typeId":2,
"date":"2019-05-21 09:00:00"
},
{
"typeId":4,
"date":"2019-05-21 10:00:00"
}
]
}
}
What I need is the order's date while I know which type I need (4).
An order can have a number of dates identified by their typeId. typeId 4 is not always in second position.
SELECT JSON_UNQUOTE(JSON_SEARCH(`json`, 'one', 4, NULL, '$.dates[*].typeId'))
// gives me: $.dates[1].typeId
My first thought now was to REPLACE typeId with date, but that complains about mixed collations.
How would I (more elegantly) reference the 'date' value here?
Also, the query is supposed to be the expression of a GENERATED column in my table. Since date id4 is not necessarily there for every order, I tried this:
SELECT IF(4 IN (JSON_EXTRACT(json, '$.dates[*].typeId')), 'yes', 'no')
// above condition evaluates to [2, 4]
I have trimmed away '[' and ']' but then it only gives me a 'yes' if 4 is first in the array (is it an array?).
So (without brackets):
[4, 7] -> yes
[2, 4] -> no
I'm assuming this doesn't get recognized as an array of values but a string. Then why does it give me 'yes' if my needle is in first position?
Instead of yes and no I obviously want to use the date and NULL.
The MySQL JSON functions are quite new to me. So maybe someone could point me in the right direction?
Try:
Option 1:
SELECT
JSON_UNQUOTE(
JSON_EXTRACT(
`json`,
REPLACE(
JSON_UNQUOTE(
JSON_SEARCH(
`json`,
'one',
4,
NULL,
'$.order.dates[*].typeId'
)
),
'typeId',
'date'
)
)
) `date`;
Option 2:
SELECT
IF(
JSON_CONTAINS(
JSON_EXTRACT(
`json`,
'$.order.dates[*].typeId'
),
4
),
'yes',
'no'
) `exists`;
See dbfiddle.

MYSQL-how to insert geometry data

I'm trying to insert geometry data using MYSQL, here is a code-example:
CREATE TABLE CARTESIAN
(
ROW_ID INT NOT NULL,
G GEOMETRY,
PRIMARY KEY(ROW_ID)
)
INSERT INTO CARTESIAN
VALUES (0,'POINT(1 1)'),
(1,'LINESTRING(2 1, 6 6)'),
(2,'POLYGON((0 5, 2 5, 2 7, 0 7, 0 5))')
When I run the INSERT I receive the message "Cannot get geometry object from data you send to the GEOMETRY field".
Can you explain me where I'm wrong?
You need to convert the text representations into GEOMETRY before you can insert them using the ST_GeomFromText function. Try this:
CREATE TABLE CARTESIAN
(
ROW_ID INT NOT NULL,
G GEOMETRY,
PRIMARY KEY(ROW_ID)
);
INSERT INTO CARTESIAN
VALUES (0,ST_GeomFromText('POINT(1 1)')),
(1,ST_GeomFromText('LINESTRING(2 1, 6 6)')),
(2,ST_GeomFromText('POLYGON((0 5, 2 5, 2 7, 0 7, 0 5))'));
SELECT * FROM CARTESIAN
Output:
ROW_ID G
0 [GEOMETRY - 25 B]
1 [GEOMETRY - 45 B]
2 [GEOMETRY - 97 B]

How to select data from jsonb column?

I have got one column with type jsonb. The data in this column looks as below
{
"random_number1":
{
"random_number2":
{
"Param1": 2,
"Param2": 0,
"Param3": 0,
"Param4": 6,
"Param5": 3
}
}
}
How to write select for this column if I want f.e. all rows where "Param3"=6 ?
I tried something like that
SELECT * FROM table WHERE column->'Param3' #> '6'::jsonb;
It depends on your expectations.
Get the value of a specified path:
select *
from my_table
where my_col->'random_number1'->'random_number2'->>'Param3' = '6'
Get the value of the key Param3 of any object on the third level:
select t.*
from my_table t,
jsonb_each(my_col) as value1(key1, value1),
jsonb_each(value1) as value2(key2, value2)
where jsonb_typeof(my_col) = 'object'
and jsonb_typeof(value1) = 'object'
and value2->>'Param3' = '6';
In the second case you may want to use distinct as the query may yield duplicated rows.