How to SELECT JSON data stored in as text - mysql

I have to extract data from a MariaDB database where the owners have stored JSON data in varchar fields in the form:
[-100, -18.3, -10.1, 2.2, 5.8, ...]
I would like to be able to select individual entries from each of these JSON encoded text fields.
I have been reading about the many features of JSON support in MariaDB and I have looked at many examples of how data can be stored as JSON in text fields, but they all would require changes to how the data is inserted and/or the schema.
I cannot change the DB in any way. I have ReadOnly access.
The owners of the DB are currently using MariaDB 10.0, but I may be able to get them to upgrade to 10.1
In short, given the following (very simple example), how can I select the 2nd element in the ‘data’ field?
I assume using the JSON features is the way to go (given all the data is JSON), but is there another way? Performance isn't all that important.
MariaDB [mtest]> show columns from cal from mtest;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| data | varchar(255) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
1 row in set (0.00 sec)
MariaDB [mtest]> select * from cal;
+---------+
| data |
+---------+
| [10.1,12.0,16.78,18.9] |
+---------+
1 row in set (0.00 sec)

If you can upgrade to 10.1 (from MariaDB 10.1.9) via CONNECT can use JsonGet_Real function.
Try:
MariaDB [_]> SELECT VERSION();
+-----------------+
| VERSION() |
+-----------------+
| 10.1.14-MariaDB |
+-----------------+
1 row in set (0.00 sec)
MariaDB [_]> INSTALL SONAME 'ha_connect';
Query OK, 0 rows affected (0.01 sec)
MariaDB [_]> CREATE FUNCTION `jsonget_real` RETURNS REAL SONAME 'ha_connect.so';
Query OK, 0 rows affected (0.00 sec)
MariaDB [_]> DROP TABLE IF EXISTS `cal`;
Query OK, 0 rows affected, 1 warning (0.01 sec)
MariaDB [_]> CREATE TABLE IF NOT EXISTS `cal` (
-> `data` VARCHAR(255)
-> );
Query OK, 0 rows affected (0.00 sec)
MariaDB [_]> INSERT INTO `cal`
-> (`data`)
-> VALUES
-> ('[10.1,12.0,16.78,18.9]');
Query OK, 1 row affected (0.00 sec)
MariaDB [_]> SELECT `data` FROM `cal`;
+------------------------+
| data |
+------------------------+
| [10.1,12.0,16.78,18.9] |
+------------------------+
1 row in set (0.00 sec)
MariaDB [_]> SELECT `jsonget_real`(`data`, '[1]', 2) FROM `cal`;
+--------------------------------+
| jsonget_real(`data`, '[1]', 2) |
+--------------------------------+
| 12.00 |
+--------------------------------+
1 row in set (0.00 sec)

Related

Is there any way to assign default DbNull value to JSON column in MySQL?

I'm using MySQL version '8.0.28' and I'm trying to assign a default value to JSON column to one table in MySQL workbench.
Have tried this Mysql set default value to a json type column but it didn't worked out.
Any pointers or help is welcomed.
If you want a NULL to be the default, you don't need to declare that. It's the "default default" so to speak.
Here are a few different ways, tested on MySQL 8.0.29.
mysql> create table mytable (id serial primary key, j json);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into mytable () values ();
Query OK, 1 row affected (0.00 sec)
mysql> insert into mytable set j = null;
Query OK, 1 row affected (0.01 sec)
mysql> insert into mytable (id) values (default);
Query OK, 1 row affected (0.00 sec)
mysql> select * from mytable;
+----+------+
| id | j |
+----+------+
| 1 | NULL |
| 2 | NULL |
| 3 | NULL |
+----+------+
You can't set a

MariaDB default function changing PK field with auto increment to null

Take the example of the following query, I am inserting data to the teams table and teamId (type: INT) is the primary key with auto-increment set to true.
'INSERT INTO `teams` (`teamId`,`teamName`,`referralCommission`,`createdAt`,`updatedAt`,`companyId`) VALUES (DEFAULT,?,?,?,?,?);'
This query runs fine on MySQL, but on MariaDB the DEFAULT is being converted to null, which I know is the normal behavior when the default is not set for a column. But in my case, the teamId is auto-incremented so the default should point to the next available id. Instead, teamId is set to 0 (converts from null) for all entries and since the teamId is primary key, I am unable to add new entries to the table.
Any way I can use the default function of MySQL in mariadb? or any other solution for this problem.
P.S I know I can remove the teamId field entirely from the query and it will work, but I need the above query to work as it is.
i cant say what you doing. which MariaDB version you are using ?
sample
MariaDB [bernd]> SELECT VERSION();
+----------------------------------------+
| VERSION() |
+----------------------------------------+
| 10.2.41-MariaDB-1:10.2.41+maria~bionic |
+----------------------------------------+
1 row in set (0.06 sec)
MariaDB [bernd]>
MariaDB [bernd]> TRUNCATE pk_default;
Query OK, 0 rows affected (0.09 sec)
MariaDB [bernd]> SELECT * FROM `pk_default`;
Empty set (0.01 sec)
MariaDB [bernd]> INSERT INTO `pk_default` (`id`, `sid`, `val`)
-> VALUES
-> (DEFAULT, 6, 45);
Query OK, 1 row affected (0.00 sec)
MariaDB [bernd]> SELECT * FROM `pk_default`;
+----+-----+------+
| id | sid | val |
+----+-----+------+
| 1 | 6 | 45 |
+----+-----+------+
1 row in set (0.00 sec)
MariaDB [bernd]> INSERT INTO `pk_default` (`id`, `sid`, `val`)
-> VALUES
-> (DEFAULT, 6, 45);
Query OK, 1 row affected (0.01 sec)
MariaDB [bernd]> SELECT * FROM `pk_default`;
+----+-----+------+
| id | sid | val |
+----+-----+------+
| 1 | 6 | 45 |
| 2 | 6 | 45 |
+----+-----+------+
2 rows in set (0.00 sec)
MariaDB [bernd]> INSERT INTO `pk_default` (`id`, `sid`, `val`)
-> VALUES
-> (DEFAULT, 6, 45);
Query OK, 1 row affected (0.00 sec)
MariaDB [bernd]> SELECT * FROM `pk_default`;
+----+-----+------+
| id | sid | val |
+----+-----+------+
| 1 | 6 | 45 |
| 2 | 6 | 45 |
| 3 | 6 | 45 |
+----+-----+------+
3 rows in set (0.01 sec)
MariaDB [bernd]>

MySQL Insert ENUM field is left blank

So i'm trying to insert data with the query below. The columns releases_isMultipack, releases_isChase, releases_hasChase and releases_isAssortment are all enum('0', '1') type. 0 and 1 represent false and true.
INSERT INTO releases (releases_uid, releases_title, releases_releaseDate, releases_boxNumber, releases_hobbyDbId, releases_isMultipack, releases_itemNumber, releases_isChase, releases_hasChase, releases_referenceUrl, releases_componentNumber, releases_isAssortment, releases_craftProductId, releases_craftComponentId)
VALUES ('fa4d5128-407a-4c2b-8970-99a36a72b030', 'Woodsy Owl', '2021-03-26T16:05:00-07:00', '', NULL, 0, '52390', 0, 1, 'woodsy-owl-1', '52390a', 0, 9518039, 9518035)
The query works fine, however just leaves the ENUM columns blank even though a value is provided in the insert statement.
Does anyone know why this is happening?
There's a difference between 0 and '0'.
Here's a demo. I get a blank if I insert 0 because that's not the value in the enum.
mysql> create table releases (releases_isMultipack enum('0','1'));
Query OK, 0 rows affected (0.06 sec)
mysql> insert into releases values (0);
Query OK, 1 row affected, 1 warning (0.03 sec)
mysql> show warnings;
+---------+------+-----------------------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------------------+
| Warning | 1265 | Data truncated for column 'releases_isMultipack' at row 1 |
+---------+------+-----------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select * from releases;
+----------------------+
| releases_isMultipack |
+----------------------+
| |
+----------------------+
1 row in set (0.00 sec)
But it works if I use '0':
mysql> insert into releases values ('0');
Query OK, 1 row affected (0.03 sec)
mysql> select * from releases;
+----------------------+
| releases_isMultipack |
+----------------------+
| |
| 0 |
+----------------------+

MySQL DEFAULT vs. MariaDB DEFAULT

I have table_a with and auto_increment column named id and string column named name.
Running the statement:
INSERT INTO table_a(id, name)VALUES(DEFAULT, 'test');
Results to (MySQL):
+----+------+
| id | name |
+----+------|
| 1 | test |
+----+------+
Running the similar statement in MariaDB results to:
+----+------+
| id | name |
+----+------|
| 0 | test |
+----+------+
Other scenario:
I tried editing the AUTO_INCREMENT value of the table to 30. MySQL inserts 30 while MariaDB inserts 0.
What is the difference of DEFAULT value in INSERT statement of MySQL and MariaDB? Is this a bug in MariaDB or it is working as intended?
This behavior is controlled by SQL_MODE='NO_AUTO_VALUE_ON_ZERO', both in MySQL and MariaDB. If you observe the difference, it's most likely because you have different sql_mode on the instances.
MariaDB [test]> CREATE TABLE t (id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY);
Query OK, 0 rows affected (0.20 sec)
MariaDB [test]> SET SQL_MODE='';
Query OK, 0 rows affected (0.00 sec)
MariaDB [test]> INSERT INTO t (id) VALUES (DEFAULT);
Query OK, 1 row affected (0.05 sec)
MariaDB [test]> SELECT * FROM t;
+----+
| id |
+----+
| 1 |
+----+
1 row in set (0.00 sec)
MariaDB [test]> DROP TABLE t;
Query OK, 0 rows affected (0.14 sec)
MariaDB [test]> CREATE TABLE t (id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY);
Query OK, 0 rows affected (0.30 sec)
MariaDB [test]> SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO';
Query OK, 0 rows affected (0.00 sec)
MariaDB [test]> INSERT INTO t (id) VALUES (DEFAULT);
Query OK, 1 row affected (0.03 sec)
MariaDB [test]> SELECT * FROM t;
+----+
| id |
+----+
| 0 |
+----+
1 row in set (0.00 sec)

Error Code: 1264. Out of range value for column 'XXX' at row 1

My stored procedure has IN parameter for page number (IN page INT)
And everything works fine for any value <= 2147483647.
And if value is > 2147483647 I get error 1264.
All this happens on 5.6.26 Community Server compiled for Linux (x86_64) and the same for 5.6.24 Community Server compiled for Win64 (x86_64)
And all of the above is fine and I understand the error.
However, on server 5.6.30-1+deb.sury.org~xenial+2 (Ubuntu) compiled for debian-linux-gnu (x86_64) this is not reproduced. Input value is just cut to 2147483647 no matter what value I pass there.
What setting is responsible for this "auto max value cap"? How can I synchronize settings on different environments without re-installation to have the same behavior?
Thank you!
Check 5.1.7 Server SQL Modes.
mysql> SELECT ##GLOBAL.SQL_MODE, ##SESSION.SQL_MODE;
+--------------------------------------------+--------------------------------------------+
| ##GLOBAL.SQL_MODE | ##SESSION.SQL_MODE |
+--------------------------------------------+--------------------------------------------+
| STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION |
+--------------------------------------------+--------------------------------------------+
1 row in set (0.00 sec)
mysql> DELIMITER //
mysql> DROP PROCEDURE IF EXISTS `sp_test`//
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> CREATE PROCEDURE `sp_test`(IN `page` INT)
-> BEGIN
-> SELECT `page`;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> CALL `sp_test`(2147483647);
+------------+
| `page` |
+------------+
| 2147483647 |
+------------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
mysql> CALL `sp_test`(2147483648);
ERROR 1264 (22003): Out of range value for column 'page' at row 1
mysql> SET ##SESSION.SQL_MODE = 'NO_ENGINE_SUBSTITUTION';
Query OK, 0 rows affected (0.00 sec)
mysql> select ##GLOBAL.SQL_MODE, ##SESSION.SQL_MODE;
+--------------------------------------------+------------------------+
| ##GLOBAL.SQL_MODE | ##SESSION.SQL_MODE |
+--------------------------------------------+------------------------+
| STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION | NO_ENGINE_SUBSTITUTION |
+--------------------------------------------+------------------------+
1 row in set (0.00 sec)
mysql> CALL `sp_test`(2147483648);
+------------+
| `page` |
+------------+
| 2147483647 |
+------------+
1 row in set (0.00 sec)
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> SHOW WARNINGS;
+---------+------+-----------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------+
| Warning | 1264 | Out of range value for column 'page' at row 1 |
+---------+------+-----------------------------------------------+
1 row in set (0.00 sec)