将SQL Result行合并在一起

时间:2012-11-15 14:35:18

标签: mysql sql pivot entity-attribute-value

我正在开发一个EAV存储系统,用于存储有关对象的无模式元数据,现在正在开发一种可搜索的方法,但大部分处理都是由数据库服务器完成的。

EAV表是:

`entityID` - INT(11)
`entity` - VARCHAR(128)
`attribute` - VARCHAR(128)
`value` - BLOB

这是我的陈述:

SELECT 
    `entity`,
    (CASE WHEN `attribute` = 'bob' THEN `value` ELSE NULL END) `bob`,
    (CASE WHEN `attribute` = 'dean' THEN `value` ELSE NULL END) `dean`
FROM `eav`

返回一组很好的行(如预期的那样),如下所示:

+----------+------+------+
|  entity  | bob  | dean |
+----------+------+------+
| testEnt  | foo  | NULL | // attribute = bob
+----------+------+------+
| testEnt  | NULL | NULL | // another test attribute
+----------+------+------+
| testEnt  | NULL | NULL | // another test attribute
+----------+------+------+
| testEnt2 | foo  | NULL | // attribute = bob
+----------+------+------+
| testEnt2 | NULL | foo  | // attribute = dean
+----------+------+------+

但是当我附上GROUP BY (Entity)时,结果变为:

+----------+------+------+
|  entity  | bob  | dean |
+----------+------+------+
| testEnt  | foo  | NULL |
+----------+------+------+
| testEnt2 | foo  | NULL |
+----------+------+------+

所以在此之后使用HAVING语法停止工作。有没有办法让返回的结果是:

+----------+------+------+
|  entity  | bob  | dean |
+----------+------+------+
| testEnt  | foo  | NULL |
+----------+------+------+
| testEnt2 | foo  | foo  |
+----------+------+------+

2 个答案:

答案 0 :(得分:3)

唯一的问题是您的记录已GROUP,但您尚未汇总字段。通过使用MAX聚合字段来尝试。

SELECT 
    `entity`,
    MAX(CASE WHEN `attribute` = 'bob' THEN `value` ELSE NULL END) `bob`,
    MAX(CASE WHEN `attribute` = 'dean' THEN `value` ELSE NULL END) `dean`
FROM `eav`
GROUP BY `entity`

答案 1 :(得分:2)

使用CASEGROUP BY应用聚合函数。由于值是字符串,因此您可以使用MAX()MIN()来返回结果:

SELECT 
    `entity`,
    Max(CASE WHEN `attribute` = 'bob' THEN `value` ELSE NULL END) `bob`,
    Max(CASE WHEN `attribute` = 'dean' THEN `value` ELSE NULL END) `dean`
FROM `eav`
group by `entity`

请参阅SQL Fiddle with Demo

如果您要返回未知数量的attribute值,则可以使用预准备语句来获取结果:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(case when attribute = ''',
      attribute,
      ''' then value end) AS ',
      attribute
    )
  ) INTO @sql
FROM eav;

SET @sql = CONCAT('SELECT entity, ', @sql, ' 
                  FROM eav 
                   GROUP BY entity');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

请参阅SQL Fiddle with Demo

两者的结果将是:

|   ENTITY | BOB |   DEAN |
---------------------------
|  testEnt | foo | (null) |
| testEnt2 | foo |    foo |