Создать итоговый результат одним запросом - PullRequest
1 голос
/ 18 августа 2010

У меня есть таблица в следующем формате.

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 ]

3 голосов
/ 18 августа 2010

Это стандартный сводный запрос:

  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

Чтобы сделать его динамическим, вам нужно использовать Синтаксис динамического SQL MySQL под названием «Подготовленные операторы» . Требуется два запроса - первый получает список значений characteristic_name, поэтому вы можете объединить соответствующую строку в выражения CASE, как вы видите в моем примере как окончательный запрос.

1 голос
/ 18 августа 2010

Вы используете антипаттерн EAV. Невозможно автоматически создать описываемую вами сводную таблицу без жесткого кодирования характеристик, которые вы хотите включить. Как упоминает @OMG Ponies, вам нужно использовать динамический SQL для генерации запроса в произвольном порядке для набора характеристик, которые вы хотите включить в результат.

Вместо этого я рекомендую вам выбирать характеристики по одной на строку, так как они хранятся в базе данных, и если вы хотите, чтобы объект приложения представлял единое проверяемое оборудование со всеми его характеристиками, вы пишете код для циклического перемещения по строкам по мере того, как извлекайте их из приложения, собирая их в объекты.

Например, в 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-запроса не требуется сложного кода.
  • Если вы забудете одну из характеристик, это решение все равно будет автоматически найдено.
  • GROUP BY в MySQL часто работает медленно, и это позволяет избежать использования GROUP BY.
...