1

这是我的 json 文档:

[
  {
    "ID":1,
    "Label":"Price",
    "Value":399
  },
  {
    "ID":2,
    "Label":"Company",
    "Value":"Apple"
  },
  {
    "ID":2,
    "Label":"Model",
    "Value":"iPhone SE"
  },
]

这是我的桌子:

 +----+------------------------------------------------------------------------------------------------------------------------------------+
 | ID | Properties                                                                                                                         |
 +----+------------------------------------------------------------------------------------------------------------------------------------+
 |  1 | [{"ID":1,"Label":"Price","Value":399},{"ID":2,"Label":"Company","Value":"Apple"},{"ID":3,"Label":"Model","Value":"iPhone SE"}]     |
 |  2 | [{"ID":1,"Label":"Price","Value":499},{"ID":2,"Label":"Company","Value":"Apple"},{"ID":3,"Label":"Model","Value":"iPhone X"}]      |
 |  3 | [{"ID":1,"Label":"Price","Value":699},{"ID":2,"Label":"Company","Value":"Apple"},{"ID":3,"Label":"Model","Value":"iPhone 11"}]     |
 |  4 | [{"ID":1,"Label":"Price","Value":999},{"ID":2,"Label":"Company","Value":"Apple"},{"ID":3,"Label":"Model","Value":"iPhone 11 Pro"}] |
 +----+------------------------------------------------------------------------------------------------------------------------------------+

这是我想在搜索查询中搜索的内容:

  SELECT *
  FROM mobiles
  WHERE ($.Label = "Price" AND $.Value < 400)
    AND ($.Label = "Model" AND $.Value = "iPhone SE")

上述查询仅用于说明目的。我只是想表达我想要表演的东西。

我也知道该表可以归一化为两个。但是这张桌子也是一个占位符桌子,我们只是说它会保持不变。

我需要知道是否可以为以下运算符查询给定的 json 结构:>, >=, <, <=, BETWEEN AND, IN, NOT IN, LIKE, NOT LIKE, <>

4

2 回答 2

1

由于 MariaDB不支持 JSON_TABLE(),并且JSON_PATH仅支持成员/对象选择器,因此在这里过滤 JSON 并不是那么简单。你可以试试这个查询,它试图克服这些限制:

with a as (
  select 1 as id, '[{"ID":1,"Label":"Price","Value":399},{"ID":2,"Label":"Company","Value":"Apple"},{"ID":3,"Label":"Model","Value":"iPhone SE"}]' as properties union all
  select 2 as id, '[{"ID":1,"Label":"Price","Value":499},{"ID":2,"Label":"Company","Value":"Apple"},{"ID":3,"Label":"Model","Value":"iPhone X"}]' as properties union all
  select 3 as id, '[{"ID":1,"Label":"Price","Value":699},{"ID":2,"Label":"Company","Value":"Apple"},{"ID":3,"Label":"Model","Value":"iPhone 11"}]' as properties union all
  select 4 as id, '[{"ID":1,"Label":"Price","Value":999},{"ID":2,"Label":"Company","Value":"Apple"},{"ID":3,"Label":"Model","Value":"iPhone 11 Pro"}]' as properties
)
select *
from a
where json_value(a.properties,
    /*Get path to Price property and replace property name to Value*/
    replace(replace(json_search(a.properties, 'one', 'Price'), '"', ''), 'Label', 'Value')
  ) < 400
  and json_value(a.properties,
    /*And the same for Model name*/
    replace(replace(json_search(a.properties, 'one', 'Model'), '"', ''), 'Label', 'Value')
  ) = "iPhone SE"

| id | properties
+----+------------
| 1  | [{"ID":1,"Label":"Price","Value":399},{"ID":2,"Label":"Company","Value":"Apple"},{"ID":3,"Label":"Model","Value":"iPhone SE"}]

db<>在这里摆弄。

于 2020-12-22T07:59:04.763 回答
1

我不会使用字符串函数。MariaDB 中缺少的是将数组取消嵌套到行的能力——但它具有我们访问数据所需的所有 JSON 访问器。使用这些方法而不是字符串方法可以避免极端情况,例如当值包含嵌入的双引号时。

您通常会在一个数字表的帮助下取消对数组的嵌套,该表的行数至少与最大数组中的元素一样多。一种动态生成的方法是 row_number()针对具有足够行的表 - 比如说sometable

您可以按如下方式取消嵌套数组:

select t.id,
    json_unquote(json_extract(t.properties, concat('$[', n.rn, '].Label'))) as label,
    json_unquote(json_extract(t.properties, concat('$[', n.rn, '].Value'))) as value
from mytable t
inner join (select row_number() over() - 1 as rn from sometable) n
    on n.rn < json_length(t.properties)

剩下的只是聚合:

select t.id
from (
    select t.id,
        json_unquote(json_extract(t.properties, concat('$[', n.rn, '].Label'))) as label,
        json_unquote(json_extract(t.properties, concat('$[', n.rn, '].Value'))) as value
    from mytable t
    inner join (select row_number() over() - 1 as rn from sometable) n
        on n.rn < json_length(t.properties)
) t
group by id
having 
    max(label = 'Price' and value + 0 < 400) = 1 
    and max(label = 'Model' and value = 'iPhone SE') = 1
    

DB Fiddle 上的演示

于 2020-12-22T15:13:51.987 回答