【问题标题】:MySql select dynamic row values as column namesMySql 选择动态行值作为列名
【发布时间】:2014-10-14 04:17:12
【问题描述】:

这是我给定的表格:

+---------+------------+-------------------+--------------------------+---------------+---------------+
| exec_id | project_id | flow_id           | job_id                   | start_time    | end_time      |
+---------+------------+-------------------+--------------------------+---------------+---------------+
|   10919 |         16 | my_flow_cleanup   | init                     | 1408480308611 | 1408480308686 |
|   10919 |         16 | my_flow_cleanup   | job_id_1                 | 1408480309212 | 1408480309426 |
|   10919 |         16 | my_flow_cleanup   | job_id_2                 | 1408480308721 | 1408480308776 |
|   10919 |         16 | my_flow_cleanup   | job_id_3                 | 1408480308827 | 1408480309171 |
+---------+------------+-------------------+--------------------------+---------------+---------------+

我想实现这样的选择:

exec_id     init_start            init_end            job_id_1_start       job_id_1_end       job_id_2_start        job_id_2_end        job_id_3_start      job_id_3_end
10919       1408480308611         1408480308686       1408480309212        1408480309426      1408480308721         1408480308776       1408480308827       1408480309171

我在这上面花了两天多的时间,但收效甚微。 This question 帮助了我,但并不完全。如您所见,另一个问题涉及获取 2 列并将它们转换为 2 行。但我必须取 3 列并将它们转换为 2 行。

谁能帮我解决这个问题?在 MySQL 中甚至可能吗?

编辑 1

感谢 Khalid Junaid 的回答,它解决了我的问题。我必须再做一次修改。我必须按 start_time 升序对选定的列进行排序。

例如:

+---------+------------+-------------------+----------+---------------+---------------+
| exec_id | project_id | flow_id           | job_id   | start_time    | end_time      |
+---------+------------+-------------------+----------+---------------+---------------+
|   10919 |         16 | my_flow_cleanup   | init     | 10            | 15            |
|   10919 |         16 | my_flow_cleanup   | job_id_1 | 30            | 40            |
|   10919 |         16 | my_flow_cleanup   | job_id_2 | 40            | 50            |
|   10919 |         16 | my_flow_cleanup   | job_id_3 | 20            | 25            |
+---------+------------+-------------------+----------+---------------+---------------+

当前查询将返回:

exec_id     init_start            init_end            job_id_1_start       job_id_1_end       job_id_2_start        job_id_2_end        job_id_3_start      job_id_3_end
10919       10                    15                  30                   40                 40                    50                  20                  25

我需要:

exec_id     init_start            init_end            job_id_3_start       job_id_3_end       job_id_1_start        job_id_1_end        job_id_2_start      job_id_2_end
10919       10                    15                  20                   25                 30                    40                  40                  50

请注意,现在根据 start_time 更改了列的顺序。

我尝试用temporary tables 和views 来做这件事,我认为这很容易。不幸的是,我没有创建表/创建视图权限。有没有办法在没有临时表和视图的情况下实现这一点?

【问题讨论】:

  • job_id 是否限制为 3 或者 b 可以超过 3?
  • 为什么要为每条记录单独的表?相反,你为什么不能用通用字段(job_id、init_start、init_end、job_id_start、..)创建一个新表?
  • @MKhalidJunaid: job_id 可以大于 3
  • @vengets:我没有创建新表。我必须查询此表并将结果附加到文件中
  • 你想使用过程/函数吗?

标签: mysql sql pivot-table


【解决方案1】:

是的,这在 MySQL 中是可能的,但是对于任何 SQL 数据库,您都不能进行 动态 从它找到的数据值创建列的查询。查询的列必须在您准备查询时固定。因此,您必须事先知道要成为列的不同值。这可能需要另一个查询。在所有 SQL 数据库中都是如此,而不仅仅是 MySQL。

SELECT exec_id,
 MIN(CASE job_id WHEN 'init' start_time END) AS init_start,
 MIN(CASE job_id WHEN 'init' end_time END) AS init_end,
 MIN(CASE job_id WHEN 'job_id_1' start_time END) AS job_id_1_start,
 MIN(CASE job_id WHEN 'job_id_1' end_time END) AS job_id_1_end
FROM `this_is_my_given_table`
GROUP BY exec_id

这基本上是对每个不同的作业 ID 进行硬编码,但这是必要的。

【讨论】:

    【解决方案2】:

    从参考问题的使用group_concat 的方法来看,您可以这样做,但请注意一件事,因为您的工作ID 每个exec_id 组都会增加,那么group_concat 方法将不是最佳的,因为它的默认长度为1024 个字符连接并且对于您的动态列,这肯定会超过该限制,但可以增加此限制,如documentation中所述

    SET @sql = NULL;
    
    SELECT GROUP_CONCAT(DISTINCT
      CONCAT('MAX(CASE WHEN job_id = ''',
             job_id, 
             ''' THEN start_time END) `',
             job_id,
             '_start`',
             ',',
             'MAX(CASE WHEN job_id = ''',
             job_id,
             ''' THEN end_time END) `',
             job_id,
             '_end`' 
             )
    
     )
      INTO @sql
      FROM t;
    
    SET @sql = CONCAT('SELECT exec_id, ', @sql, ' 
                         FROM t 
                        GROUP BY exec_id');
    
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
    

    Fiddle Demo

    【讨论】:

    • 我解决了上述问题。这是小提琴:sqlfiddle.com/#!2/a88db/5。但我必须对架构进行一些小改动,execution_jobs 和execution_flows 有几个我无法更改的同名列(start_time 和end_time)。我正在尝试这个sqlfiddle.com/#!2/1b8c46/1,但它不起作用。你能帮我吗?谢谢
    • @Bhushan 从您的上述评论中不清楚您能否提出一个包含所有详细信息的新问题,如果您希望我查看新问题,请在此处提供链接
    • 我添加了另一个子问题。你能看看吗?谢谢。
    • @Bhushan 您能否针对上述问题提出新问题,并提供有关该问题的所有信息,这对我和新访问者都有好处,也请在这里为我提供新问题的链接
    猜你喜欢
    • 2012-06-11
    • 1970-01-01
    • 2013-04-05
    • 1970-01-01
    • 2020-11-08
    • 1970-01-01
    • 2012-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多