SQL 查询以过滤字符串化的 json 数组

A SQL query to filter through a stringified json array

我正在努力编写一个 sql 查询,该查询可以以某种方式从 table 中检索结果。

我有一个 table 可能有以下类型的数据。在这个 table 中,antecendents 列中的值是以字符串形式排列的 skus 列表

Id | antecendents | ...         | ....
1  | ["a","b","c"]| ...         | .....
2  | ["a"]        | ...         | .....
3  | ["a","b"]    | ...         | .....
4  | ["a","c"]    | ...         | .....
5  | ["a","c","x"]| ...         | .....
6  | ["a","y","c"]| ...         | .....
7  | ["c"]        | ...         | .....

现在假设我有一组 SKU(例如“a”和“c”)

我只想从 table 中检索那些包含“a”和“c”的所有组合但没有其他内容的行。所以我的查询会 return 以下

Id | antecendents | ...         | ....
2  | ["a"]        | ...         | .....
4  | ["a","c"]    | ...         | .....
7  | ["c"]        | ...         | .....

我可以编写一个查询来获取部分结果并在代码中进一步过滤它,但是在 sql 查询中完成这一切会更有效。

如有任何帮助,我们将不胜感激。

我想到了这个解决方案。去除 'a' 元素,然后使用生成的数组去除 'c' 元素,然后将其与空 json_array() 进行比较。如果前因减去'a'元素减去'c'元素是一个空数组,那么就没有其他元素了,也就是你想要的其中一行。

select id, antecedents from (
  select id, antecedents, coalesce(json_remove(antecedents, json_unquote(json_search(antecedents, 'one', 'a'))), antecedents) as a from mytable ) as t
where coalesce(json_remove(a, json_unquote(json_search(a, 'one', 'c'))), a) = json_array()

结果:

+----+-------------+
| id | antecedents |
+----+-------------+
|  2 | ["a"]       |
|  4 | ["a", "c"]  |
|  7 | ["c"]       |
+----+-------------+

但老实说,写这么复杂的代码是不切实际的。写难、读难、调试难、维护修改难。

永远记住这个智慧:

"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian Kernighan

如果不使用 JSON 数组会容易得多。每行只存储一个元素。

create table mytable2 (id int, antecedent varchar(10), primary key (id, antecedent));

insert into mytable2 values
(1, 'a'), (1,'b'), (1,'c'),
(2, 'a'),
(3, 'a'), (3, 'b'),
(4, 'a'), (4, 'c'),
(5, 'a'), (5, 'c'), (5, 'x'),
(6, 'a'), (6, 'y'), (6, 'c'),
(7, 'c');

现在更容易构思查询。您甚至可以 return 值集作为 JSON 数组。

select m1.id, json_arrayagg(m1.antecedent) as antecedents
from mytable2 m1 left outer join mytable2 as m2
  on m1.id = m2.id and m2.antecedent not in ('a','c')
where m2.id is null
group by m1.id

结果:

+----+-------------+
| id | antecedents |
+----+-------------+
|  2 | ["a"]       |
|  4 | ["a", "c"]  |
|  7 | ["c"]       |
+----+-------------+

如果您想将元素视为集合中的离散元素,关系数据库已经有支持的方法。不要使用 JSON.