'Use JSON_TABLE cross join on subquery mysql
I am at a loss on how to use a JSON_TABLE in mysql 8.0 only on a small part of another table, if the selection of this part involves a JOIN or a subquery:
Let's start with a table predictions which contains the value of a predictions as well as some foreign key
SELECT * FROM predictions
id | ml_model_id | value
+--+-------------+------
1 | 1 | [{"class": "dog", "confidence": 1}, {"class": "cat", "confidence": 0.03}]
Here is the selection of the whole table that works well:
SELECT *
FROM predictions,
JSON_TABLE(
predictions.value,
"$[*]"
COLUMNS (class VARCHAR(30) PATH "$.class",
confidence FLOAT PATH "$.confidence")
) myjson
Original problem: a subquery cannot be used as a table to build the JSON_TABLE on
However, this does not work anymore if I replace the predictions table by a subquery of it
SELECT * FROM (
SELECT * FROM predictions
WHERE ml_model_id = 1
# Do any type of filtering here, or even none at all
) preds,
JSON_TABLE(
preds.value,
"$[*]"
COLUMNS (class VARCHAR(30) PATH "$.class",
confidence FLOAT PATH "$.confidence")
) myjson
)
I will get an SQL Error 1210 "Incorrect argument to JSON_TABLE"
Limited workaround: If the filtering is on a table column, you can use WHERE...
My first thought was to take the filtering outside of the subquery, which to a certain extent work:
SELECT * FROM predictions,
JSON_TABLE(...) myjson
WHERE predictions.ml_model_id = 1
This solution works, already comes off as unelegant to me, because it means that the , between predictions and JSON_TABLE is an implicit lateral join instead of a cross join (Edit: note that even when using a CROSS JOIN instead of the , does an implicit lateral join)
...But it does not work if your filtering involves JOINs
However, if instead of a WHERE i'd want to filter by using a JOIN, I will get an even more cryptic error:
SELECT * FROM predictions,
JSON_TABLE(...) myjson
INNER JOIN ml_models
ON ml_models.id = predictions.ml_model_id
AND ml_models.usage = "classification"
will raise an SQL ERROR [1054] Unknown column 'predictions.ml_model_id' in 'on clause'... Why would this column not be found ? Running without the inner join actually returns it !
Unelegant workaround that seems to work in all cases: Using EXISTS in WHERE clause
Simply replacing the INNER JOIN by a WHERE EXISTS works, but this is really counterintuitive to work that way.
SELECT * FROM predictions,
JSON_TABLE(...) myjson
WHERE EXISTS (SELECT 1 FROM ml_models
WHERE ml_models.id = predictions.ml_model_id
AND ml_models.usage = "classification")
Is there something that I don't understand on JSON_TABLE that prevents me to use a subquery on it ?
Solution 1:[1]
I finally managed to make it work with a subquery as first part of the join, by casting the JSON field as a JSON again in the JSON_TABLE
SELECT * FROM (
SELECT * FROM predictions
WHERE ml_model_id = 1
# Do any type of filtering here, or even none at all
) preds,
JSON_TABLE(
CAST(preds.value AS JSON),
"$[*]"
COLUMNS (class VARCHAR(30) PATH "$.class",
confidence FLOAT PATH "$.confidence")
) myjson
)
I am however even more at a loss on why this would work, so I will keep the question open if someone has an explanation about why it works this way and not without the cast.
Solution 2:[2]
This works for me, it appears to be an order of operations when it comes to the joins.
SELECT * FROM predictions preds
INNER JOIN ml_models
ON ml_models.id = preds.ml_model_id
AND ml_models.usage = "classification",
JSON_TABLE(preds.value, ...) myjson
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | LoicM |
| Solution 2 | TK-421 |
