Как использовать group concat в подготовленном операторе MySQL? - PullRequest
0 голосов
/ 06 мая 2020

У меня есть эта таблица данных о продукте:

+--------+--------+------------+
| item_id| amount |    date    |
+--------+--------+------------+
|      4 |    100 | 01-04-2020 |
|      6 |    200 | 01-04-2020 |
|      9 |    300 | 01-04-2020 |
|      4 |    400 | 01-04-2020 |
|      4 |    300 | 02-04-2020 |
|      6 |    150 | 02-04-2020 |
|      6 |    150 | 02-04-2020 |
|      9 |    700 | 02-04-2020 |
+--------+--------+------------+

Я хочу сделать запрос, который поворачивает эту таблицу, чтобы ItemId находился на стороне столбца, который отображает сумму всех items:

+------------+-----+-----+-----+
|    date    |  4  |  6  |  9  |
+------------+-----+-----+-----+
| 01-04-2020 | 400 | 200 | 400 |
| 02-04-2020 | 300 | 300 | 700 |
+------------+-----+-----+-----+

Мне удалось написать запрос, который мог бы это сделать:

SELECT 
    date,
    SUM(IF(item_id = '1', item_record.amount, NULL)) AS 1,
    SUM(IF(item_id = '2', item_record.amount, NULL)) AS 2,
    SUM(IF(item_id = '3', item_record.amount, NULL)) AS 3,
    COUNT(*) AS Total 
FROM   item_record
GROUP BY date WITH ROLLUP

Но запрос был жестко запрограммирован так, чтобы отображались только столбцы с item_id 1, 2, и 3. Мне нужно сделать его динамическим c.

Обыскивая StackOverflow, я обнаружил этот вопрос . После принятого ответа я попытался превратить его в подготовленный оператор

SET @sql = NULL;


SELECT 
GROUP_CONCAT(DISTINCT
    CONCAT(
      'SUM(IF(item_record.item_id = "',item_record.item_id,'", item_record.amount, NULL)) 
      AS ',item_record.item_id
    )
  ) INTO @sql
FROM item_record;


SET @sql = 
CONCAT('SELECT date,    
              ',@sql,',
              COUNT(*)  AS Total 
        FROM   item_record
        GROUP BY date WITH ROLLUP
       ');

PREPARE stmt FROM @sql;
EXECUTE stmt;

Но я обнаружил ошибку:

SQL Ошибка [1064] [42000]: у вас есть ошибка в синтаксисе SQL; проверьте руководство, соответствующее вашей версии сервера MySQL, чтобы найти правильный синтаксис для использования рядом с

'4,SUM(IF(item_record.item_id = "6", item_record.amount, NULL)) AS 6' at line 2

Где я сделал не так? Это похоже на простую синтаксическую ошибку, но я занимался этим несколько часов и до сих пор не знал, в чем дело.

Ответы [ 2 ]

1 голос
/ 06 мая 2020

Честно говоря, если приложение не способно превратить следующее во что-то красивое, то, вероятно, не стоит возиться с ...

DROP TABLE IF EXISTS product_data;

CREATE TABLE product_data
(id SERIAL PRIMARY KEY
,item_id INT NOT NULL
,amount INT NOT NULL
,date DATE NOT NULL
);

INSERT INTO product_data VALUES
(1,4,100,'2020-04-01'),
(2,6,200,'2020-04-01'),
(3,9,300,'2020-04-01'),
(4,4,400,'2020-04-01'),
(5,4,300,'2020-04-02'),
(6,6,150,'2020-04-02'),
(7,6,150,'2020-04-02'),
(8,9,700,'2020-04-02');           


SELECT item_id
     , date
     , SUM(amount) x 
  FROM product_data 
 GROUP 
    BY date
     , item_id;
+---------+------------+------+
| item_id | date       | x    |
+---------+------------+------+
|       4 | 2020-04-01 |  500 |
|       6 | 2020-04-01 |  200 |
|       9 | 2020-04-01 |  300 |
|       4 | 2020-04-02 |  300 |
|       6 | 2020-04-02 |  300 |
|       9 | 2020-04-02 |  700 |
+---------+------------+------+
1 голос
/ 06 мая 2020

Ваш исходный запрос уже как синтаксические ошибки. Если вы попытаетесь его выполнить, вы получите ту же ошибку, что и в случае с подготовленным оператором:

У вас есть ошибка в синтаксисе SQL; проверьте руководство, соответствующее вашей версии сервера MySQL, чтобы найти правильный синтаксис для использования рядом с '1,

SUM(IF(item_id = '2', item_record.amount, NULL)) AS 2,
SUM(IF(item_id' at line 3

Проблема заключается в имени псевдонима столбца в наборе результатов: 1 (или что-либо, что начинается с числа) не является действительным идентификатором - если вы не окружите его обратными кавычками.

Я бы сформулировал ваш код как:

SET @sql = NULL;

SELECT GROUP_CONCAT(DISTINCT
    CONCAT('SUM(CASE WHEN item_id = ', item_id, ' THEN amount END) AS `', item_id, '`')
) INTO @sql
FROM item_record;

SET @sql = CONCAT(
    'SELECT date, ', 
     @sql, 
     ', COUNT(*)  AS Total FROM item_record GROUP BY date WITH ROLLUP'
);

Обратите внимание, что здесь используется стандартный CASE выражений вместо IF() (оба действительны в MySQL). Кроме того, это обрабатывает item_id как число, а не как строку - потому что это то, на что это похоже.

...