I'm working with DB2 using a "data" column containing a JSON object stored as a CLOB.
To simplify my scenario consider this (easier) example:
CREATE TABLE Students (
StudentID INT PRIMARY KEY NOT NULL,
Name VARCHAR(255),
PrefMeal CLOB
);
INSERT INTO Students (StudentID, Name, PrefMeal) VALUES
(1, 'John Doe', '{"pizza":[{"id":2,"name":"Pizza Patate e Salsiccia","ingredients":["Potatoes","Mozzarella Cheese","Sausage"]}]}'),
(2, 'Jane Doe', '{"pizza":[{"id":1,"name":"Pizza Margherita","ingredients":["Tomato Sauce","Mozzarella Cheese","Oregano"]}]}'),
(3, 'Mario Rossi', '{"pizza":[{"id":2,"name":"Pizza Patate e Salsiccia","ingredients":["Potatoes","Mozzarella Cheese","Sausage"]},{"id":1,"name":"Pizza Margherita","ingredients":["Tomato Sauce","Mozzarella Cheese","Oregano"]}]}');
SELECT s.*
FROM Students s
Which of course returns all the students:
STUDENTID|NAME |PREFMEAL |
---------+-----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1|John Doe |{"pizza":[{"id":2,"name":"Pizza Patate e Salsiccia","ingredients":["Potatoes","Mozzarella Cheese","Sausage"]}]} |
2|Jane Doe |{"pizza":[{"id":1,"name":"Pizza Margherita","ingredients":["Tomato Sauce","Mozzarella Cheese","Oregano"]}]} |
3|Mario Rossi|{"pizza":[{"id":2,"name":"Pizza Patate e Salsiccia","ingredients":["Potatoes","Mozzarella Cheese","Sausage"]},{"id":1,"name":"Pizza Margherita","ingredients":["Tomato Sauce","Mozzarella Cheese","Oregano"]}]}|
The Problem
Now, suppose that I would like to select all the students which have at least a "Pizza Margherita" as a prefered meal. Normally an IN operator would make the magic but $.pizza is a JSON_ARRAY and the simpler solution does not works (so json path direct access too)...
I thought that I could use JSON_QUERY function to perform something similar to:
SELECT S.NAME, JSON_QUERY(S.PREFMEAL, '$.pizza[*].name' WITH CONDITIONAL WRAPPER) AS PREF_PIZZA
FROM STUDENTS s
WHERE JSON_QUERY(S.PREFMEAL, '$.pizza[*].name') IN ('Pizza Margherita');
Which of course does not return any rows since JSON_ARRAY and IN operators works differently rather than a simpler ARRAY.
The only solution I've found so far is the following one, which of course is not feasible for some IN comparison (too expensive/long):
I don't like the only "solution" I've found so far (it's more a workaround tbh), which I think it's not feasible and too expensive in cost and length of the query (multiple values in IN would be trasformed in many OR conditions):
SELECT *
FROM STUDENTS s
WHERE (JSON_QUERY(S.PREFMEAL, '$.pizza.name' WITH CONDITIONAL WRAPPER)) LIKE ('%"Pizza Margherita"%')
That returns correctly:
STUDENTID|NAME |PREFMEAL |
---------+-----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
2|Jane Doe |{"pizza":[{"id":1,"name":"Pizza Margherita","ingredients":["Tomato Sauce","Mozzarella Cheese","Oregano"]}]} |
3|Mario Rossi|{"pizza":[{"id":2,"name":"Pizza Patate e Salsiccia","ingredients":["Potatoes","Mozzarella Cheese","Sausage"]},{"id":1,"name":"Pizza Margherita","ingredients":["Tomato Sauce","Mozzarella Cheese","Oregano"]}]}|
I'm running out of ideas, I've even tried with JSON_TABLE but can't find a way to properly use it in the Where clause. Any help will be appreciated!
SELECT S.STUDENTID, S.NAME, JT.PIZZAS FROM Students S, JSON_TABLE(S.PREFMEAL, 'strict $' COLUMNS( PIZZAS VARCHAR(100) FORMAT JSON PATH '$.pizza.name' WITH CONDITIONAL WRAPPER) ERROR ON ERROR) AS JTWhich returns something like3 Mario Rossi ["Pizza Patate e Salsiccia","Pizza Margherita"]