mysql表关系及如何查询键/值表

kq4fsx7k  于 2021-06-21  发布在  Mysql
关注(0)|答案(4)|浏览(274)

我有以下表格结构:
产品(id、名称……)

+-----+------------+
| id  | name       |
+-----+------------+
|   1 | Product #1 |
|   2 | Product #2 |
|   3 | Product #3 |
|   4 | Product #4 |
+-----+------------+

属性(id、标题…)

+-----+------------+
| id  | title      |
+-----+------------+
|   1 | shape      |
|   2 | colour     |
|   3 | height     |
|   4 | weight     |
+-----+------------+

选项(id、标题…)

+-----+------------+
| id  | title      |
+-----+------------+
|   1 | round      |
|   2 | square     |
|   3 | oval       |
|   4 | red        |
|   5 | blue       |
|   6 | green      |
|   7 | tall       |
|   8 | short      |
|   9 | heavy      |
|  10 | light      |
+-----+------------+

第四个(productattribute-id、product\u id、attribute\u id、option\u id),希望得到“所有又高又重的红色圆形产品”:

+-----+------------+--------------------+
| id  | product    | attribute | option |
+-----+------------+--------------------+
|   1 | Product #1 | shape     | round  |
|   2 | Product #2 | shape     | oval   |
|   3 | Product #3 | shape     | round  |
|   4 | Product #4 | shape     | square |
|   5 | Product #1 | color     | green  |
|   6 | Product #2 | color     | red    |
|   7 | Product #3 | height    | tall   |
|   8 | Product #4 | height    | short  |
|   9 | Product #2 | weight    | heavy  |
|  10 | Product #1 | weight    | light  |
+-----+------------+--------------------+

我还不是sql高手,也许我的想法行不通。
编辑:
问题1。问题是我如何做到这一点?比如所有的红色,高,重的产品。
以下查询没有达到我的目的:
1:

SELECT ProductAttributes.product_id, ProductAttributes.id FROM ProductAttributes 
WHERE (ProductAttributes.attribute_id = 1 AND ProductAttributes.option_id = 1) 
AND (ProductAttributes.attribute_id = 3 AND ProductAttributes.option_id = 4);

2:

SELECT DISTINCT ProductAttributes.product_id, ProductAttributes.id FROM ProductAttributes 
WHERE (ProductAttributes.attribute_id = 1 AND ProductAttributes.option_id = 1) 
OR (ProductAttributes.attribute_id = 3 AND ProductAttributes.option_id = 4);

注意:我有意在我的查询中放入2个变量,因为真正的变量还有很多。

iyfjxgzm

iyfjxgzm1#

对于键/值方法,我会使用复合键来提高一致性:
属性(属性号,标题),pk=属性号

+--------------+------------+
| attribute_no | title      |
+--------------+------------+
| 1            | shape      |
| 2            | colour     |
| ...          | ...        |
+--------------+------------+

属性\选项(属性\否,选项\否,值),pk=属性\否,选项\否

+--------------+-----------+------------+
| attribute_no | option_no | value      |
+--------------+-----------+------------+
| 1            | 1         | round      |
| 1            | 2         | square     |
| 2            | 1         | green      |
| 2            | 2         | red        |
| ...          | ...       | ...        |
+--------------+-----------+------------+

产品(产品编号,产品名称,…),pk=产品编号

+------------+--------------+
| product_no | product_name |
+------------+--------------+
| 7352871    | Product #1   |
| 8956443    | Product #2   |
| ...        | ...          |
+------------+--------------+

产品属性(产品编号、属性编号、选项编号),pk=产品编号、属性编号

+------------+--------------+-----------+
| product_no | attribute_no | option_no |
+------------+--------------+-----------+
| 7352871    | 1            | 1         |
| 7352871    | 2            | 1         |
| 8956443    | 1            | 2         |
| 8956443    | 2            | 1         |
+------------+--------------+-----------+

(并且您希望该表的属性\u no+选项\u no上有一个索引。)
这个 product_attributes 主键保证每个产品每个属性只获得一个值。嗯,这对身高、体重等都有好处。如果你想要一个产品有多种颜色等,但是你需要这样的颜色 product_attributes 表格包括 option_no 在主键中。您可能会得到用于唯一属性和多个属性的单独表。也许以后你甚至想引入具有可选和强制性属性的产品组(冰箱有能量等级,t恤没有)。因此,整个概念可能会增长,但上面的表格应该给你一个如何最好地处理这个问题的想法。
查询所有又高又重的红色圆形产品:

select * 
from product
where product_no in
(
  select product_no
  from product_attributes
  where (attribute_no, option_no) = 
  (
    select ao.attribute_no, ao.option_no 
    from attribute_option ao
    join attribute a on a.attribute_no = ao.attribute_no
    where a.title = 'colour'
    and ao.value = 'red'
  )
)
and product_no in
(
  select product_no
  from product_attributes
  where (attribute_no, option_no) = 
  (
    select ao.attribute_no, ao.option_no 
    from attribute_option ao
    join attribute a on a.attribute_no = ao.attribute_no
    where a.title = 'shape'
    and ao.value = 'round'
  )
)
and product_no in (...)
and product_no in (...);

或更短的聚合:

select * 
from product
where product_no in
(
  select pa.product_no
  from product_attributes pa
  join attribute a on a.attribute_no = pa.attribute_no
  join attribute_option ao on a.attribute_no = pa.attribute_no
                           and a.option_no = pa.option_no
  group by pa.product_no
  having sum(a.title = 'colour' and ao.value = 'red') > 0
     and sum(a.title = 'shape' and ao.value = 'round') > 0
     and sum(a.title = 'height' and ao.value = 'tall') > 0
     and sum(a.title = 'weight' and ao.value = 'heavy') > 0
)
rur96b6h

rur96b6h2#

所以您需要根据productattribute表中的选项进行选择
在表中存储数据的更好方法是对第四列使用unique/id/主键值,然后您可以

SELECT * FROM ProductAttribute as attr
INNER JOIN Product as product ON product.id=attr.product_id 
INNER JOIN Attribute as attr2 ON attr2.id=attr.attribute_id
WHERE attr.option=“round” OR attr.option=“red”

我希望这对你有帮助!

izkcnapc

izkcnapc3#

在网上搜索“mysql key-value-table”(感谢@thorsten kettner提供关键字,因为我缺乏术语),我最终得到了如下结果:

SELECT Product.id FROM Product
INNER JOIN ProductAttributes PA_1 ON
    Product.id = PA_1.product_id
INNER JOIN ProductAttributes PA_2 ON
    Product.id = PA_2.product_id
WHERE
    (PA_1.attribute_id = 1 and PA_1.option_id = 1)
AND
    (PA_2.attribute_id = 3 and PA_2.option_id = 4);

基本上,只要在查询中使用一个新属性,一个不同的 INNER JOIN 需要条件。
就“性能”而言,一个相当明显的打击将会发生。
根据这个和这个键/值表不应该用于过滤,但在这一点上我没有选择,所以它将由缓存服务器保存一天。
我已经根据我的答案(不需要 GROUP BY 在我的例子中,由于我不使用聚合函数,所以使用键/值对从表中筛选和分组数据

9w11ddsr

9w11ddsr4#

键/值表令人讨厌。所以,如果可以的话,尽量避免。那你就有这些table了:
表格形状

+--------+
| shape  |
+--------+
| round  |
| oval   |
| round  |
| square |
+--------+

表格颜色

+--------+
| color  |
+--------+
| green  |
| red    |
+--------+

工作台高度

+--------+
| height |
+--------+
| tall   |
| short  |
+--------+

工作台重量

+--------+
| weight |
+--------+
| heavy  |
| light  |
+--------+

餐桌产品

+-------------+--------------+--------+--------+--------+--------+
| product_no  | product name | shape  | color  | height | weight |
+-------------+--------------+--------+--------+--------+--------+
|   14214     | Product #1   | round  | red    | tall   | heavy  |
|   22312     | Product #2   | oval   |        | short  | heavy  |
|   35757     | Product #3   | square | green  | tall   | heavy  |
|   42468     | Product #4   |        | red    | short  | light  |
+-------------+--------------+--------+--------+--------+--------+

查询

select * 
from products
where shape = 'round' 
  and color = 'red' 
  and height = 'tall' 
  and weight = 'heavy';

顺便说一句,你也可以用ID做同样的事情。所以所有的查找表都会得到一个id(round=1,oval=2。。。绿色=1,红色=2,…),产品表将不再包含单词,而是包含ID。查询将是:

select * 
from products
where shape_id = (select id from shapes where shape = 'round')
  and color_id = (select id from colors where color = 'red')
  and height_id = (select id from heights where height = 'tall')
  and weight_id = (select id from weights where weight = 'heavy';

相关问题