MySQL表关系以及如何查询Key / value表

时间:2018-04-20 16:27:52

标签: mysql database-design

我有以下表结构:

产品(id,name,...)

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

属性(id,title,...)

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

选项(id,title ...)

+-----+------------+
| 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_id,attribute_id,option_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大师,也许我的想法无法奏效。

编辑:

Q1。问题是我该如何实现这一目标?例如,获得所有红色,高大,重型产品。

以下查询无法实现我的目的:

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个变量,因为真正的变量还有更多。

4 个答案:

答案 0 :(得分:1)

键/值表是令人讨厌的。如果可以,请避免使用它们。那你就有这些表:

表格形状

+--------+
| 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  |
+-------------+--------------+--------+--------+--------+--------+

查询

oraoledb12.dll

顺便说一下,你可以对ID做同样的事情。因此,所有查找表都将获得一个ID(round = 1,oval = 2,... green = 1,red = 2,...),并且product表将不再包含单词,而是ID。然后查询将是:

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

答案 1 :(得分:1)

因此,您希望根据ProductAttribute表中的选项

进行选择

在表中存储数据的更好方法是对第四列使用unique / id / primary key值,然后就可以了

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”

我希望这对你有所帮助!

答案 2 :(得分:1)

Fot键/值方法我使用复合键来提高一致性:

属性(attribute_no,title),PK = attribute_no

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

attribute_option(attribute_no,option_no,value),PK = attribute_no,option_no

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

产品(product_no,product_name,...),PK = product_no

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

product_attributes(product_no,attribute_no,option_no),PK = product_no,attribute_no

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

(你想在这个表的attribute_no + option_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
)

答案 3 :(得分:0)

在网上搜索“mysql键值表”(感谢@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条件。

在“表现”方面会发生相当明显的打击。

根据thisthis,不应使用键/值表进行过滤,但此时我别无选择,因此将由缓存服务器来保存当天

我的答案基于此(在我的情况下不需要GROUP BY,因为我不使用聚合函数)Filtering and Grouping data from table with key/value pairs