使用一个查询创建摘要结果

时间:2010-08-18 18:17:48

标签: sql mysql pivot entity-attribute-value

我有一张格式如下的表格。

mysql> describe unit_characteristics;
+----------------------+------------------+------+-----+---------+----------------+
| Field                | Type             | Null | Key | Default | Extra          |
+----------------------+------------------+------+-----+---------+----------------+
| id                   | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| uut_id               | int(10) unsigned | NO   | PRI | NULL    |                |
| uut_sn               | varchar(45)      | NO   |     | NULL    |                |
| characteristic_name  | varchar(80)      | NO   | PRI | NULL    |                |
| characteristic_value | text             | NO   |     | NULL    |                |
| creation_time        | datetime         | NO   |     | NULL    |                |
| last_modified_time   | datetime         | NO   |     | NULL    |                |
+----------------------+------------------+------+-----+---------+----------------+

每个uut_sn都有多个特征名称/值对。我想用MySQL来生成一个表

+----------------------+-------------+-------------+-------------+--------------+
| uut_sn | char_name_1 | char_name_2 | char_name_3 | char_name_4 | ...          |
+----------------------+-------------+-------------+-------------+--------------+
| 00000  | char_val_1  | char_val_2  | char_val_3  | char_val_4  | ...          | 
| 00001  | char_val_1  | char_val_2  | char_val_3  | char_val_4  | ...          |
| 00002  | char_val_1  | char_val_2  | char_val_3  | char_val_4  | ...          |
| .....  | char_val_1  | char_val_2  | char_val_3  | char_val_4  | ...          |
+----------------------+------------------+------+-----+---------+--------------+

只用一个查询就可以了吗?

谢谢, -Peter

2 个答案:

答案 0 :(得分:3)

这是标准的透视查询:

  SELECT uc.uut_sn,
         MAX(CASE 
               WHEN uc.characteristic_name = 'char_name_1' THEN uc.characteristic_value 
               ELSE NULL 
             END) AS char_name_1,
         MAX(CASE 
               WHEN uc.characteristic_name = 'char_name_2' THEN uc.characteristic_value 
               ELSE NULL 
             END) AS char_name_2,
         MAX(CASE 
               WHEN uc.characteristic_name = 'char_name_3' THEN uc.characteristic_value 
               ELSE NULL 
             END) AS char_name_3,
    FROM unit_characteristics uc
GROUP BY uc.uut_sn

要使其动态化,您需要使用MySQL's dynamic SQL syntax called Prepared Statements。它需要两个查询 - 第一个获取characteristic_name值的列表,因此您可以将相应的字符串连接到CASE表达式中,就像您在我的示例中看到的最终查询一样。

答案 1 :(得分:1)

您正在使用EAV反模式。无法自动生成您描述的数据透视表,无需对要包含的特征进行硬编码。正如@OMG Ponies所提到的那样,您需要使用动态SQL以自定义方式对查询进行通用,以获得要包含在结果中的特征集。

相反,我建议您每行获取一个特征,因为它们存储在数据库中,如果您希望应用程序对象代表具有其所有特征的单个UUT,您可以编写代码来循环遍历行在您的应用程序中获取它们,将它们收集到对象中。

例如在PHP中:

$sql = "SELECT uut_sn, characteristic_name, characteristic_value 
        FROM unit_characteristics";
$stmt = $pdo->query($sql);

$objects = array();
while ($row = $stmt->fetch()) {
  if (!isset($objects[ $row["uut_sn"] ])) {
      $object[ $row["uut_sn"] ] = new Uut();
  }
  $objects[ $row["uut_sn"] ]->$row["characteristic_name"] 
                            = $row["characterstic_value"];
}

与查询中的硬编码特征名称解决方案相比,这有一些优势:

  • 此解决方案只需要一个SQL查询而不是两个。
  • 构建动态SQL查询不需要复杂的代码。
  • 如果您忘记了其中一个特征,此解决方案无论如何都会自动找到它。
  • MySQL中的GROUP BY通常很慢,这避免了GROUP BY。