【问题标题】:transpose column headers to rows in postgresql将列标题转置为 postgresql 中的行
【发布时间】:2012-05-24 09:20:14
【问题描述】:

我有一个看起来像这样的视图

          value1count     value2count value3count
          ----------------------------------------
             25              35          55

我需要将列标题转换成行,所以我需要它看起来像

          Values              Count
         -----------------------------
           value1count         25
           value2count         35
           value3count         55

我可以通过选择单个列名作为第一列和数据作为第二列来做到这一点,然后对所有列进行相同的合并。

有没有更好的方法来做到这一点? 我正在使用 PosgreSQL 8.1,因此没有可使用的枢轴运算符。

感谢您提前回复。

【问题讨论】:

  • 是的,我们正在升级到最新版本..可能在夏末....谢谢
  • 这样的列(以及这样的问题)通常表明设计存在缺陷。您提到了涉及的 VIEW,因此您的表可能并非如此。但是,如果该视图反映了实际的表结构,请考虑重新设计

标签: sql postgresql


【解决方案1】:

Crosstab 只做与您需要相反的事情,但这应该对您有所帮助:

首先创建 8.4 中包含的 unnest() 函数,有关说明,请参阅 here

然后你可以这样做(基于this 帖子):

SELECT
   unnest(array['value1Count', 'value2Count', 'value3Count']) AS "Values",
   unnest(array[value1Count, value2Count, value3Count]) AS "Count"
FROM view_name
ORDER BY "Values"

我可以验证这在 8.4 中是否有效,但因为我没有 8.1,所以我不能保证它会同样有效。

【讨论】:

  • 这太棒了..在 8.1 中运行良好..我的联合查询用了 10 秒,而这个 unnest 查询只用了 3 秒..非常感谢 PinnyM。
  • 刚刚在 postgresql 11 中尝试过,它开箱即用。
  • SELECT unnest(array['x1','x2','x3','x4','x5','x6','x7','x8','x9',' x10','x11','x12','x13','x14','x15','x16']) opciones, unnest(array[x1,x2,x3,x4,x5,x6,x7,x8, x9,x10,x11,x12,x13,x14,x15,x16]) marcado FROM control_xopcion_table where handler_id = 76 and idemergencia = 2573
  • @PinnyM 假设将来我们有更多的列要添加到表中,那么有没有办法让我们更动态地填充数组?
  • @AdarshRavi 您可以使用下面这个答案中提到的 hstore 方法。
【解决方案2】:

我通过使用hstore 的功能实现了您的目标:

SELECT (x).key, (x).value
FROM
  ( SELECT EACH(hstore(t)) as x
    FROM   t
  ) q;

如果您的“待分解”视图或表中有多行(此处称为t),您可能需要在中间表q 中插入一个附加标识符,例如:

SELECT id, (x).key, (x).value
FROM
  ( SELECT id, EACH(hstore(t)) as x
    FROM   t
  ) q;

参考:hstore documentation

【讨论】:

  • +1,这里的优点是避免在查询中命名列。显然是it doesn't perform quite as well as unnest,但程度不高。
  • 这是一个绝妙的解决方案,谢谢!唯一的问题是列顺序搞砸了。你知道如何解决这个问题吗?
【解决方案3】:

我希望做一些与此类似的事情,以便更轻松地处理来自 bash 脚本的表信息。结果证明告诉 psql 将表列显示为行非常容易:

psql mydbname -x -A -F= -c "select * from blah where id=123"
  • -x 是输出的枢轴。
  • -A 删除了多余的间距。
  • -F= 将列名和值之间的| 替换为=

这当然不会在 SQL 中工作,它只会修改 psql 发生格式输出的方式。

【讨论】:

  • 谢谢!如果您在交互式 psql 会话期间需要这种行为,您可以使用 \x on 甚至 \x auto 在输出表对于您的终端来说太宽时切换到该模式。
【解决方案4】:

我也遇到过类似的情况。我将查询包装在 with 语句中,然后为每一行执行一堆 UNION ALLs。在我的情况下,如果我有多个记录,则 ncm_id 会有所不同,因此我继续将其添加到结果集中的列列表中。这可能不是最好的方法,但它适用于我的用例。

 WITH query_a AS (
     SELECT
       fin_item.item_number || ' - ' || fin_item.item_descrip1 fin_item,
       fin_ls.ls_number,
       ls_sort.sortby_employeeid,
       ls_sort.ncm_id,
       ls_sort.created_at,
       ls_sort.updated_at,
       ls_sort.sort_qty,
       ls_sort.initial_scan_time,
       ls_sort.ncm_scan_time,
       ls_sort.badge_scan_time,
       ls_sort.computer_name,
       ls_sort.number_of_ops,
       ls_sort.ncm_item_scan_time,
       sort_by.name sort_by,
       tblncm.instructions,
       tblncm.ncm_comments
     FROM public.item AS fin_item
       INNER JOIN public.ls AS fin_ls ON fin_item.item_id = fin_ls.ls_item_id
       INNER JOIN stone.ls_sort ON fin_ls.ls_id = ls_sort.ls_id
       INNER JOIN stone.vw_mssql_employees AS sort_by ON ls_sort.sortby_employeeid = sort_by.employeeid
       INNER JOIN stone.tblncm ON ls_sort.ncm_id = tblncm.ncm_id
       LEFT JOIN stone.equips AS mach_equips ON ls_sort.mach_equip_id = mach_equips.id
       LEFT JOIN stone.equips AS mold_equips ON ls_sort.mold_equip_id = mold_equips.id
     WHERE 1 = 1
           AND fin_ls.ls_number ILIKE 'S143027526190' || '%'
 )
   SELECT *
   FROM (
     (SELECT 'fin_item' my_column, fin_item::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'ls_number' my_column, ls_number::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'sortby_employeeid' my_column, sortby_employeeid::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'ncm_id' my_column, ncm_id::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'created_at' my_column, created_at::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'updated_at' my_column, updated_at::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'sort_qty' my_column, sort_qty::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'initial_scan_time' my_column, initial_scan_time::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'ncm_scan_time' my_column, ncm_scan_time::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'badge_scan_time' my_column, badge_scan_time::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'computer_name' my_column, computer_name::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'number_of_ops' my_column, number_of_ops::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'ncm_item_scan_time' my_column, ncm_item_scan_time::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'sort_by' my_column, sort_by::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'instructions' my_column, instructions::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
      UNION ALL
     (SELECT 'ncm_comments' my_column, ncm_comments::TEXT my_value, ncm_id::TEXT my_ncm FROM query_a)
   ) as query_guy
 ORDER BY my_ncm;

【讨论】:

  • 非常好的例子。如果您将其修改为与问题的具体情况兼容的简化版本,那就更好了。
  • 我想知道查询的性能是否与 UNNEST 相关。
【解决方案5】:

我可能不明白...但我这样做的方式是同时选择 DISTINCT,然后选择我需要的平均列值。像这样:

SELECT DISTINCT contributing_factor_vehicle_1, AVG(number_of_cyclist_injured) FROM "table1".motor_vehicle_collisions_crashes 
GROUP BY contributing_factor_vehicle_1
ORDER BY avg(number_of_cyclist_injured) desc

这就是创造这样的东西:

顺便说一句,这是纽约市机动车碰撞数据。

【讨论】:

    猜你喜欢
    • 2017-09-18
    • 2012-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-27
    • 2013-05-13
    • 2021-07-06
    • 2015-09-11
    相关资源
    最近更新 更多