Search code examples
mysqljsonmariadbmariadb-connect-engine

How to SELECT JSON data stored in as text


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)

Solution

  • 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)