Преобразование строки в столбцы в MySQL - PullRequest
1 голос
/ 28 мая 2019

Моя таблица исходит из вывода хранимой процедуры. Похоже:

col1 
A 
B
C
D

Может быть меньше или равно 5 строкам.
Я хочу, чтобы это выглядело так

Column1  Column2 Column3  Column4  column5 
A          B      C         D       NULL

Есть ли способ достичь этого в MYSQL?

Ответы [ 2 ]

2 голосов
/ 28 мая 2019

Ниже MySQL 8.0 подход становится намного более сложным ..

Простое объяснение о сложной части первого запроса
Подзапрос в пределах

  SELECT 
     GROUP_CONCAT(t.col1 ORDER BY col1 ASC) AS cvs
   , COUNT(*) AS t_count
  FROM 
   t

создает список значений через запятую. Затем генератор чисел SQL в сочетании с вложенными функциями SUBSTRING_INDEX() разделяет значения, разделенные запятыми, на записи. Который затем объединяется в одну строку с помощью GROUP_CONCAT() в пользовательскую переменную, в основном я генерирую динамический SQL, который выглядит как '<value>' AS Column<number>[, ...], это то, что SELECT @aggregateSQLPart; показывает вам

Запрос

SET @aggregateSQLPart = NULL; 

# set max of GROUP_CONCAT higher as it defaults to 1024 bytes. 
SET SESSION group_concat_max_len = @@max_allowed_packet;

SELECT 
 DISTINCT
   GROUP_CONCAT(CONCAT("'", 
    SUBSTRING_INDEX(
       SUBSTRING_INDEX(
          t.cvs
         , ','
       , number_generator.number
      )
      , ','
      , -1 
    ) , "'" , " AS Column", number_generator.number 
 ))
INTO @aggregateSQLPart                          
FROM (
   SELECT 
     @row := @row + 1 AS number
   FROM (
      SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION   SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
      ) row1
      CROSS JOIN (
      SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION  SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
    ) row2
    CROSS JOIN (
      SELECT @row := 0 
    ) init_user_params 
  ) AS number_generator
 CROSS JOIN (
  SELECT 
     GROUP_CONCAT(t.col1 ORDER BY col1 ASC) AS cvs
   , COUNT(*) AS t_count
  FROM 
   t
 ) AS t

WHERE
 number BETWEEN 1 AND t_count;

SELECT @aggregateSQLPart;    


SET @SQL = CONCAT("
 SELECT 
 "
 , @aggregateSQLPart                                                 
);

SELECT @SQL;    

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

Результат

| Column1 | Column2 | Column3 | Column4 | Column5 |
| ------- | ------- | ------- | ------- | ------- |
| A       | B       | C       | D       | E       |

см. демо

Примечание не сомневайтесь в производительности, которая в среднем выполняется на 5-10 мс на «тестовом» сервере. Также обратите внимание, что я выбираю пользовательские переменные, чтобы вы могли видеть, что происходит в между.

2 голосов
/ 28 мая 2019

В MySQL 8+ есть довольно простой способ сделать это, используя ROW_NUMBER вместе с сводным запросом:

WITH cte AS (
    SELECT col1, ROW_NUMBER() OVER (ORDER BY col1) rn
    FROM yourTable
)

SELECT
    MAX(CASE WHEN rn = 1 THEN col1 END) AS Column1,
    MAX(CASE WHEN rn = 2 THEN col1 END) AS Column2,
    MAX(CASE WHEN rn = 3 THEN col1 END) AS Column3,
    MAX(CASE WHEN rn = 4 THEN col1 END) AS Column4,
    MAX(CASE WHEN rn = 5 THEN col1 END) AS Column5
FROM cte;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...