0

Alright so I'll try to explain it as simple as possible; consider that I have two database tables (MySQL Server / MariaDB, database-related tasks coded in procedural style in PHP using prepared statements):

  1. in one, I have a column of datatype JSON, whose content corresponds to sth like {name1:info,name2:info}

  2. In another one, I have simple non-json records, having a structure like:

name  | status
------+--------
name1 | statusX
------+--------
name2 | statusY

My Goal: I need to retrieve the name2 from table 1), but I also need to retrieve the status of the person having that same name (which in this case is statusY). Note that, for the retrieval of name2, I cannot rely on indexes of the json object (name2 may be the first key of the json object).

How I would do it so far: A) Get the name2 from table 1) in a first query, sanitize it, and B) use it in the second query which then correctly retrieves the statusY

Both statements A) and B) are parametrized prepared sql statements, triggered by an AJAX Call at a regular interval (AJAX Polling).

Given that these database queries are thus executed frequently, I want them to be executed as fast as possible, and thus ideally reduce my two queries above to a single one. My problem: I need the result of statement A) to execute statement B), so I cannot summarize the two queries into a single prepared statement, as prepared statements cannot contain multiple sql statements. The best solution to reach what I want is create a stored procedure like:

SET @name = SELECT ..... FROM table_1; SELECT .... FROM table_2;

And then execute it as parametrized prepared statement; is that correct? I'm not at all experienced with stored procedures in MySQL Server, didn't really need them yet, but they seem to be the only solution if you want to wrap > 1 sql statements into a single prepared statement. Is this assumption, and thus the conclusion that I gotta create a stored procedure to reach what I want, correct?

IMPORTANT NOTE: I don't know the name I need to query. From the two names of the json column of table 1), I only know the other name. In other words, I have one name of a person X, and I want to get the status of all the persons which have been associated with that person X in table 1), while the status of each person is listed in table 2), to avoid to have duplicate status storage in the DB. ATM, I retrieve the other names of each relation record from DB 1) by using a conditional statement saying sth like

UPDATE

See added answer below, got it working.

DevelJoe
  • 856
  • 1
  • 10
  • 24
  • MySQL or SQL Server, they are different database engines? – Zhorov Jul 23 '20 at 19:09
  • Sorry typo; basically I just wanted to say that I use a MariaDB on a MySQL Server; to let readers know which kind of prepared statements and stored procedures I'm talking about – DevelJoe Jul 23 '20 at 19:11
  • 1
    One would generally solve this by joining the two tables, but since your data in table1 isn't stored in a relational format (it's json) this will be a smidge more difficult. I think [this question](https://stackoverflow.com/questions/39818296/using-mysql-json-field-to-join-on-a-table) has what you are looking for. The join is performed on the result of a [`json_search`](https://mariadb.com/kb/en/json_search/) of the json column. In the end you'll have a single query that contains your `name2` and it's `status` as the result set. – JNevill Jul 23 '20 at 19:19
  • The problem is that I need to retrieve the name lying in the json doc first, and then make the second query based on the retrieved name. Given that the name to retrieve may be at first or second position of the json column of table 1), I cannot "set" it to a selected value in my sql statement, but I need to define it as user-defined variable first to use it later on, no? Later on I could do it with a JOIN statement, yes, but my main issue is that I need a second statement using a retrieved name, and thus a switch to stored procedures..? – DevelJoe Jul 23 '20 at 19:26
  • What you can do (using the query of the answer below) is join your second table in twice using both Name1 and Name2. You can stick both statuses in the output and then when the data is returned to your php you can figure out which name you actually wanted and grab its respective status. 1 trip to the database and a single set of parameters. That may or may not be quicker/better than your current approach of two distinct queries though. – JNevill Jul 23 '20 at 21:37
  • Cheers mate, and what do you think about the approach of using a stored procedure of two subsequent statements, where the first returns the name2 as variable, and the second queries table 2 with it..? – DevelJoe Jul 24 '20 at 07:47
  • Never mind, my solution added below worked, thanks a lot man! – DevelJoe Jul 24 '20 at 09:49

2 Answers2

1

You can query JSON data type with MySQL (if version > 5.7), and thus you can simply do everything with a single query

Give this a try

SELECT t1.name1, t1.name2, t2.status
FROM
(
  SELECT  JSON_EXTRACT(your_json_column, "$.name1") AS name1,
        JSON_EXTRACT(your_json_column, "$.name2") AS name2
  FROM table1
  WHERE JSON_EXTRACT(your_json_column, "$.name1") = 'info'
) t1
INNER JOIN table2 t2 ON t2.`name`=t1.name2

Adapt the name of your_json_column. Also I assumed that you wanted to search the name2 of a specific name1, thus my WHERE clause, remove it if it was a false assumption.

Thomas G
  • 9,886
  • 7
  • 28
  • 41
  • Thanks mate, but there's one thing I didn't mention: I don't know the name of the two I need to query; I only know the name I don't need (e.g. if I need to use name2 for query B), I only know name1 when firing the query). I retrieve name2 by using a conditional statement saying sth like ```CASE WHEN JSON_VALUE(JSON_KEY(names),'$[0]') = name1 THEN JSON_VALUE(JSON_KEY(names),'$[1]') ELSE JSON_VALUE(JSON_KEY(names),'$[0]') END``` – DevelJoe Jul 23 '20 at 19:32
0

Okay got it working, pretty much thanks to the solution proposed by Thomas G and some hints of JNevill (cheers guys!):

SELECT t1.info1, t1.info2, t1.info3, t1.other_name, t2.status FROM (
    SELECT
    field1 AS info1,
    field2 AS info2,
    field3 AS info3,
    CASE
    WHEN JSON_VALUE(JSON_KEYS(json_names_column),"$[0]") = 'name1'
    THEN JSON_VALUE(JSON_KEYS(json_names_column),"$[1]")
    ELSE JSON_VALUE(JSON_KEYS(json_names_column),"$[0]")
    END
    AS other_name
    FROM table1
    WHERE id = 345
) t1 INNER JOIN table2 t2 ON t1.other_name = t2.name;

Note that I used JSON_VALUE(JSON_KEYS()) instead of JSON_EXTRACT, to only return the needed name as name data of t1, and because I don't know the name to retrieve before the query, so I cannot use the WHEREclause proposed by Thomas G.

DevelJoe
  • 856
  • 1
  • 10
  • 24