【问题标题】:MySQL: how to convert to EAV - Part 3?MySQL:如何转换为 EAV - 第 3 部分?
【发布时间】:2015-07-08 18:24:51
【问题描述】:

以前的相关帖子:

给定一张桌子:

TABLE: foo
===============================
| id | first_name | last_name |
===============================
| 1  | John       | Doe       |
| 2  | Jane       | Smith     |
| 3  | Ronald     | McDonald  |
-------------------------------

如何获取此表并将其转换为这些表(EAV 实现)?:

TABLE: attribute
===========================
| id | fk_id | attribute  |
===========================
| 1  | 100   | first_name |
| 2  | 100   | last_name  |
---------------------------

TABLE: value
=========================================
| id | attribute_id | row_id | value    |
=========================================
| 1  | 1            | 1      | John     |
| 2  | 2            | 1      | Doe      |
| 3  | 1            | 2      | Jane     |
| 4  | 2            | 2      | Smith    |
| 5  | 1            | 3      | Ronald   |
| 6  | 2            | 3      | McDonald |
-----------------------------------------

注意事项:

  • 将提供attribute.fk_id。
  • value.row_id 用于标识值在原始表中如何分组为记录。

更新:另外,我如何查询 EAV 表,以便让它再次看起来像表 foo。

【问题讨论】:

  • 是的,比如take。使用 EAV 获得更多游戏时间。

标签: mysql database entity-attribute-value


【解决方案1】:

我给@Phil 填充EAV 表的解决方案+1。一次插入一个属性。

这是另一种反转 EAV 转换的解决方案:

SELECT v.row_id AS id,
  MAX(IF(a.attribute='first_name',v.value,NULL)) AS first_name,
  MAX(IF(a.attribute='last_name',v.value,NULL)) AS last_name
FROM value v INNER JOIN attribute a
  ON v.attribute_id = a.id 
GROUP BY v.row_id

除了使用 EAV 之外,您已将所有值放入 VARCHAR(255) 或其他列中,因此您丢失了有关原始列的相应数据类型的信息。

如果不对属性名称进行硬编码(如@Phil 所示的连接或我所示的列),真的没有办法“动态地”执行此操作。本质上和trying to write dynamic pivot queries是一样的问题。

我在我的演示文稿Practical Object-Oriented Models in SQL 和我的书中SQL Antipatterns: Avoiding the Pitfalls of Database Programming 中写了更多关于 EAV 的内容。

【讨论】:

  • 您的演示文稿和书籍链接是相同的。另外,我认为您缺少一些括号
  • 糟糕!谢谢,我已经修好了。
【解决方案2】:

我认为您唯一的希望是使用foo 表。 bar 没有 ID 基本上没用。

尝试这样的事情(假设attribute.id 是一个自增主键)

INSERT INTO `attribute` (`fk_id`, `attribute`)
VALUES (100, 'first_name');

INSERT INTO `value` (`attribute_id`, `row_id`, `value`)
SELECT LAST_INSERT_ID(), `id`, `first_name`
FROM `foo`;

INSERT INTO `attribute` (`fk_id`, `attribute`)
VALUES (100, 'last_name');

INSERT INTO `value` (`attribute_id`, `row_id`, `value`)
SELECT LAST_INSERT_ID(), `id`, `last_name`
FROM `foo`;

要重建foo 表,试试这个

SELECT
    `fn`.`row_id` AS `id`,
    `fn`.`value` AS `first_name`,
    `ln`.`value` AS `last_name`
FROM `value` `fn`
INNER JOIN `attribute` `fn_a`
    ON `fn`.`attribute_id` = `fn_a`.`id`
    AND `fn_a`.`attribute` = 'first_name'
INNER JOIN `value` `ln`
    ON `fn`.`row_id` = `ln`.`row_id`
INNER JOIN `attribute` `ln_a`
    ON `ln`.`attribute_id` = `ln_a`.`id`
    AND `ln_a`.`attribute` = 'last_name'

呃,谢谢你提醒我为什么我讨厌这种模式

【讨论】:

  • 好的,我可以摆脱bar。是否有一个查询可以将 EAV 转换回原始表?现在,我只想做一个 SELECT,而不是 INSERT 结果。
猜你喜欢
  • 2011-10-24
  • 1970-01-01
  • 2020-09-22
  • 2022-11-30
  • 2013-02-13
  • 1970-01-01
  • 1970-01-01
  • 2022-11-17
  • 2011-08-06
相关资源
最近更新 更多