MySQL: выбрать, сгруппировать и преобразовать строки в отдельные столбцы :) - PullRequest
0 голосов
/ 24 апреля 2020

Мне нужно попросить вас помочь с MySQL запросом на выбор.
Специфика c Пример: сотрудники с супругом и детьми.
У меня есть 2 таблицы, которые уже объединены в одну, и теперь мне нужно:
1, выберите данные, сгруппировав их по полю 'emp'
2, преобразуйте результат по следующим правилам:

  • только одна строка с определенным emp (emp-A , emp-B, emp- C)
  • каждый родственник (супруг и дети) в последующих столбцах (сначала супруг, потом дети)

Таблица (фактически две соединенные таблицы):

+---------+-----------+-----------+------------+
| emp     | relation  | relative  | birthdate  |
+---------+-----------+-----------+------------+
| emp-A   | spouse    | spouse-A  | 1970-xx-xx |
| emp-A   | kid       | kid-A1    | 1971-xx-xx |
| emp-A   | kid       | kid-A2    | 1972-xx-xx |
| emp-A   | kid       | kid-A3    | 1973-xx-xx |
| emp-B   | spouse    | spouse-B  | 1980-xx-xx |
| emp-B   | kid       | kid-B1    | 1981-xx-xx |
| emp-B   | kid       | kid-B2    | 1982-xx-xx |
| emp-C   | kid       | kid-C1    | 1991-xx-xx |
| emp-C   | kid       | kid-C2    | 1992-xx-xx |
+---------+-----------+-----------+------------+

Желаемый результат:

+---------+-----------+-------------+-----------+-------------+-----------+-------------+-----------+-------------+
| emp     | spouse    | birthdate   | kid1      | birthdate1  | kid2      | birthdate2  | kid3      | birthdate3  |
+---------+-----------+-------------+-----------+-------------+-----------+-------------+-----------+-------------+
| emp-A   | spouse-A  | 1970-xx-xx  | kid-A1    | 1971-xx-xx  | kid-A2    | 1972-xx-xx  | kid-A3    | 1973-xx-xx  |
| emp-B   | spouse-B  | 1980-xx-xx  | kid-B1    | 1981-xx-xx  | kid-B2    | 1982-xx-xx  |           |             |
| emp-C   |           |             | kid-C1    | 1991-xx-xx  | kid-C2    | 1992-xx-xx  |           |             |
+---------+-----------+-------------+-----------+-------------+-----------+-------------+-----------+-------------+


После нескольких часов неудачных попыток поиски, я сдался.
Я буду очень благодарен за некоторые подсказки, возможно ли добиться чего-то подобного (один запрос на выбор был бы лучшим вариантом для меня).
Заранее спасибо.

Отвечая на emsoff, исходные таблицы:
сотрудники:

+----+---------+
| id | emp     |
+----|---------+
|  1 | emp-A   |
|  2 | emp-B   |
|  3 | emp-C   |
+----|---------+

родственники:

+----+---------+-----------+-----------+------------+
| id | emp_id  | relation  | relative  | birthdate  |
+----+---------+-----------+-----------+------------+
|  1 |       1 | spouse    | spouse-A  | 1970-xx-xx |
|  2 |       1 | kid       | kid-A1    | 1971-xx-xx |
|  3 |       1 | kid       | kid-A2    | 1972-xx-xx |
|  4 |       1 | kid       | kid-A3    | 1973-xx-xx |
|  5 |       2 | spouse    | spouse-B  | 1980-xx-xx |
|  6 |       2 | kid       | kid-B1    | 1981-xx-xx |
|  7 |       2 | kid       | kid-B2    | 1982-xx-xx |
|  8 |       3 | kid       | kid-C1    | 1991-xx-xx |
|  9 |       3 | kid       | kid-C2    | 1992-xx-xx |
+----|---------+-----------+-----------+------------+

Табл присоединяется к employee.id =latives.emp_id

1 Ответ

1 голос
/ 24 апреля 2020

Ваши данные несколько сложны в обработке.

Чтобы создать сводную таблицу, столбцы должны быть уникальными ie, даже более того, чтобы пять kis могли апараренироваться.

Это довольно некрасиво и работает с myslq 5.7

схема (MySQL v5.7)

CREATE TABLE employees (
  `id` INTEGER,
  `emp` VARCHAR(5)
);

INSERT INTO employees
  (`id`, `emp`)
VALUES
  ('1', 'emp-A'),
  ('2', 'emp-B'),
  ('3', 'emp-C');

CREATE TABLE relatives (
  `id` INTEGER,
  `emp_id` INTEGER,
  `relation` VARCHAR(6),
  `relative` VARCHAR(8),
  `birthdate` DATE
);

INSERT INTO relatives
  (`id`, `emp_id`, `relation`, `relative`, `birthdate`)
VALUES
  ('1', '1', 'spouse', 'spouse-A', '1970-01-01'),
  ('2', '1', 'kid', 'kid-A1', '1971-01-02'),
  ('3', '1', 'kid', 'kid-A2', '1972-01-01'),
  ('4', '1', 'kid', 'kid-A3', '1973-01-01'),
  ('5', '2', 'spouse', 'spouse-B', '1980-02-01'),
  ('6', '2', 'kid', 'kid-B1', '1981-02-01'),
  ('7', '2', 'kid', 'kid-B2', '1982-02-01'),
  ('8', '3', 'kid', 'kid-C1', '1991-03-01'),
  ('9', '3', 'kid', 'kid-C2', '1992-03-01');

запрос # 1

SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'MAX(case when `relation` = "',
     `relation`,
      '" then `relation` end) AS `',
      relation, '`',
      ',MAX(case when `relation` = "',
     `relation`,
      '" then `birthdate` end) AS `',
      'birthdate_',relation, '`'      
    )
    ORDER BY rownumber
  ) INTO @sql
FROM
  (SELECT 
    `relation`
    ,rownumber
FROM 
    employees e
    INNER JOIN 
    (SELECT
    IF(`relation` = 'kid',IF (@empid = `emp_id`,@rn:= @rn+1,@rn:= 1),IF (@empid = `emp_id`,@rn:= @rn,@rn:= 0)) rownumber
     ,IF(`relation` = 'kid',CONCAT(`relation`,@rn),`relation`) relation
    , `relative`
    , `birthdate`
    ,@empid := `emp_id` emp_id
FROM
    (SELECT 
        * 
    FROM 
        relatives
    ORDER BY `emp_id`,FIELD(`relation`,"spouse","kid"),`birthdate`) rel
    ,(SELECT @empid := 0) a1
    ,(SELECT @rn := 0) a2) r ON e.id = r.emp_id) t1
    ;

SET @sql = CONCAT("SELECT MIN(`emp`), ", @sql, " 
                  FROM   (SELECT 
                            `emp_id`,
                            `emp` ,
                            `relation`
                            ,rownumber
                            , `relative`
                            , `birthdate`
                        FROM 
                            employees e
                            INNER JOIN 
                            (SELECT
                            IF(`relation` = 'kid',IF (@empid = `emp_id`,@rn:= @rn+1,@rn:= 1),IF (@empid = `emp_id`,@rn:= @rn,@rn:= 0)) rownumber
                             ,IF(`relation` = 'kid',CONCAT(`relation`,@rn),`relation`) 'relation'
                            , `relative`
                            , `birthdate`
                            ,@empid := `emp_id` 'emp_id'
                        FROM
                            (SELECT 
                                * 
                            FROM 
                                relatives
                            ORDER BY `emp_id`,FIELD(`relation`,'spouse','kid'),`birthdate`) rel
                            ,(SELECT @empid := 0) a1
                            ,(SELECT @rn := 0) a2) r ON e.id = r.emp_id) t1 
                   GROUP BY `emp_id`");
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

| MIN(`emp`) | spouse | birthdate_spouse | kid1 | birthdate_kid1 | kid2 | birthdate_kid2 | kid3 | birthdate_kid3 |
| ---------- | ------ | ---------------- | ---- | -------------- | ---- | -------------- | ---- | -------------- |
| emp-A      | spouse | 1970-01-01       | kid1 | 1971-01-02     | kid2 | 1972-01-01     | kid3 | 1973-01-01     |
| emp-B      | spouse | 1980-02-01       | kid1 | 1981-02-01     | kid2 | 1982-02-01     |      |                |
| emp-C      |        |                  | kid1 | 1991-03-01     | kid2 | 1992-03-01     |      |                |

Показать на БД Fiddle

...