我正在尝试通过替换SQL查询来规范我的MySQL 5.7数据shema和苦苦挣扎:
目前,有一个表格包含每篇文章的所有属性:
article_id | title | ref_id | dial_c_id
任务是检索与两个给定属性(ref_id和Dial_c_id)匹配的所有文章,并检索其所有其他属性。
只有一张桌子,这很简单:
SELECT *
FROM test.articles_test
WHERE
ref_id = '127712'
AND dial_c_id = 51
现在,为了标准化,我创建了第二个表,该表存储了每篇文章的属性,并删除了表文章中的那些属性:
表1:
article_id | title
表2:
article_id | attr_group | attribute
1 ref_id 51
1 dial_c_id 33
1 another 5
2 ..
我想检索所有文章详细信息,包括将这两个表shema与ref_id和Dial_c_id匹配的 ALL 属性。
这样:
SELECT
a.article_id,
a.title,
attr.*
FROM test.articles_test a
INNER JOIN attributes attr ON a.article_id = attr.article_id
AND ref_id = '127712'
AND dial_c_id = 51
这怎么办?
答案 0 :(得分:3)
您已使用实体-属性-值表记录您的属性。
这是归一化的相反。
命名归一化规则,该规则可指导您将不同的属性放入同一列。 您不能,因为这不是规范化做法。
要用当前的EAV设计完成查询,您需要对结果进行透视,以便获得与原始表一样的东西。
SELECT * FROM (
SELECT
a.article_id,
a.title,
MAX(CASE attr_group WHEN 'ref_id' THEN attribute END) AS ref_id,
MAX(CASE attr_group WHEN 'dial_c_id' THEN attribute END) AS dial_c_id
-- ...others...
FROM test.articles_test a
INNER JOIN attributes attr ON a.article_id = attr.article_id
GROUP BY a.article_id, a.title) AS pivot
WHERE pivot.ref_id = '127712'
AND pivot.dial_c_id = 51
虽然上面的查询可以产生您想要的结果,但性能会很糟糕。它必须为子查询创建一个临时表,其中包含两个表中的所有数据,然后对临时表应用WHERE子句。
在原始表的每个列中,每个属性的确要更好。
我了解到您将来会尝试考虑许多属性。这是一个普遍的问题。
查看我的回答 How to design a product table for many kinds of product where each product has many parameters
但是您不应将其称为“规范化”,因为它不是。甚至没有非规范化。这是修饰语。
您不能仅仅使用单词来描述您想要的任何东西,尤其是不能与单词的含义相反。我不能让空气从自行车轮胎中逸出,然后说:“我正在给它充气。”
您评论说,您正在尝试使数据库“可伸缩”。您还会误解“可扩展”一词的含义。通过使用EAV,您正在创建一种结构,其中所需的查询难以编写且执行效率低下,并且数据占用10倍的空间。 与可扩展性相反。
您的意思是您正在尝试创建一个可扩展的系统。这在SQL中实现很复杂,但是我在链接到的另一个Stack Overflow答案中描述了几种解决方案。您可能还会喜欢我的演示文稿Extensible Data Modeling with MySQL。