Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php MySQL:旧版本JSON的替代方案/在一列中存储和查询多个值_Php_Mysql_Json_Database_Rdbms - Fatal编程技术网

Php MySQL:旧版本JSON的替代方案/在一列中存储和查询多个值

Php MySQL:旧版本JSON的替代方案/在一列中存储和查询多个值,php,mysql,json,database,rdbms,Php,Mysql,Json,Database,Rdbms,我正在编写一个PHP软件包,其中我需要存储一组文档,每个文档都有自己的属性,这些属性在数量、名称和类型上可能有所不同,就像不同类型产品的属性可能有所不同,例如,鞋子可能有材质、颜色和样式,但智能手机可能有操作系统、重量、大小等 | id | name | |-----|------------| | 1 | Acme Shoe | | 2 | Acme Phone | 我希望能够查询我的所有文档或产品的属性。查询的范围可以从一个非常简单的WHERE attribute_

我正在编写一个PHP软件包,其中我需要存储一组文档,每个文档都有自己的属性,这些属性在数量、名称和类型上可能有所不同,就像不同类型产品的属性可能有所不同,例如,鞋子可能有材质、颜色和样式,但智能手机可能有操作系统、重量、大小等

| id  | name       |
|-----|------------|
| 1   | Acme Shoe  |
| 2   | Acme Phone |
我希望能够查询我的所有文档或产品的属性。查询的范围可以从一个非常简单的WHERE attribute_a=value_a到一组复杂得多的嵌套子句,如WHERE attribute_a=value_a或attribute_a>value_b和attribute_b,如“%pattern%”

我的理想方案是使用MySQL 5.7+和MariaDB 10.2+提供的本机JSON支持来存储每个文档的属性,并使用方便的JSON_EXTRACT函数来提取我想要查询的任何属性

| id  | name       | attributes                             |
|-----|------------|----------------------------------------|
| 1   | Acme Shoe  | {"material":"canvas","color":"black"}  |
| 2   | Acme Phone | {"os":"android","weight":100}          |


SELECT *
FROM documents
WHERE (
    JSON_EXTRACT(attributes, "$.weight") = 1
    OR JSON_EXTRACT(attributes, "$.weight") > 99
)
AND JSON_EXTRACT(attributes, "$.os") LIKE '%droid%'
不幸的是,我的包需要能够支持MySQL和MariaDB的旧版本。我曾考虑过将JSON存储在文本或长文本字段中,并在进行比较时使用正则表达式解析出所需属性的值,但我可以想象,这将是难以置信的资源密集型和速度缓慢。如果我错了,请纠正我

因此,就目前情况而言,我觉得我被锁定在了EAV类型的解决方案中:

| id  | name       |
|-----|------------|
| 1   | Acme Shoe  |
| 2   | Acme Phone |


| id  | document_id | key      | value   |
|-----|-------------|----------|---------|
| 1   | 1           | material | canvas  |
| 2   | 1           | color    | black   |
| 3   | 2           | os       | android |
| 4   | 2           | weight   | 100     |
查找带有WHERE子句的文档相对来说很简单:

SELECT DISTINCT(document_id)
FROM document_attributes
WHERE key = 'material'
AND value = 'canvas'
然而,我不知道如何实施更复杂的WHERE条款。特别是,问题在于属性存储在单独的行中。例如

获取具有画布材质且颜色为黑色的文档。 获取具有android操作系统且权重为1或大于99的文档。 如有任何意见或建议,将不胜感激

编辑

在对EAV方法进行了一些考虑之后,到目前为止,我所能想到的最好方法是针对查询中涉及的每个属性重复地将attributes表连接到documents表。从那里,我可以在WHERE子句中使用每个属性的值。例如,选择属性材质为画布或权重大于99的所有产品:

SELECT d.id AS id, a1.value AS material, a2.value AS weight
FROM documents AS d
LEFT JOIN attributes AS a1 ON a1.document_id = d.id AND a1.name = 'material'
LEFT JOIN attributes AS a2 ON a2.document_id = d.id AND a2.name = 'weight'
WHERE a1.value = 'canvas'
AND a2.value > 99
这似乎产生了:

| id | material | weight |
|----|----------|--------|
| 1  | canvas   | NULL   |
| 2  | NULL     | 100    |

假设文档id/键/值组合是唯一的,您可以执行以下操作:

从示例中选择文档id 其中'key`='material'和'value`='canvas' 或者'key`='color'和'value`='black' 按文档id分组 计数*=2; 从示例中选择文档id 其中'key`='os'和'value`='android' 或'key`='weight'和'value`=1或'value`>99 按文档id分组 计数*=2; 尝试以下SQL:


从文档中选择子字符串\索引子字符串\索引属性',,4',,-1

谢谢你的回答。我喜欢这种方法。我假设HAVING部分中的2指的是要比较的属性的数量?您知道这将如何扩展到更复杂的查询中吗?在这些查询中,我们以不同的方式比较更多的属性,并以不同的方式嵌套它们?我刚刚想到了一个可能的想法,即为每个要比较的属性连接attributes表一次,然后在这些连接的属性上构建where子句。你看到了吗?