【问题标题】:Split a column into three columns using two different characters as separators使用两个不同的字符作为分隔符将一列拆分为三列
【发布时间】:2014-08-12 21:26:20
【问题描述】:

使用 PostgreSQL,我想根据两个(不是一个)字符拆分表中某一列中出现的值。我的专栏id2 包含以下值:

chr1:10000485-10006485@NM_022787@NMNAT1

我想相应地将列分成三列(同时使用“:”和“-”字符作为分隔符:

chr1  |  10000485  | 10006485@NM_022787@NMNAT1

目前我的代码是:

select split_part(id2, ':', 1)s1,split_part(id2, ':', 2) s2, id2
from MyTable

输出如下(两列,其中 s1 和 s2 是标题):

s1    |     s2
chr1  |  10000485-10006485@NM_022787@NMNAT1

如何根据“:”和“-”拆分id2? 我可以使用s2 以某种方式进行顺序拆分吗?

我尝试使用:

select split_part(id2, ':', 1)s1,split_part(id2, ':', 2) s2, split_part(s2, '-', 2)

但是得到了错误信息:

ERROR:  column "s2" does not exist
LINE 7: ... ':', 1)s1,split_part(id2, ':', 2) s2, split_part(s2, '-', 2...
                                                             ^
********** Error **********

ERROR: column "s2" does not exist
SQL state: 42703
Character: 160

【问题讨论】:

标签: sql postgresql split pattern-matching


【解决方案1】:

您可以像这样使用“with”查询:

With q1 as (
   select split_part(id2, ':', 1) s1, split_part(id2, ':', 2) s2, id2
   from MyTable
   )
select s1, s2, split_part(s2, '-', 3) s3
from q1;

第一次通过电话接听。我稍后会更正。

【讨论】:

  • 记录一下:在这种情况下,CTE 与子查询的实现相同,只是成本更高。
【解决方案2】:

一种方法是使用regexp_split_to_table()

SELECT regexp_split_to_table(id2, '[:-]')
FROM  (VALUES ('chr1:10000485-10006485@NM_022787@NMNAT1')) tbl(id2)

多行结果:

regexp_split_to_table
----------------------
chr1
10000485
10006485@NM_022787@NMNAT1

或者regexp_split_to_array():

SELECT regexp_split_to_array(id2, '[:-]')

然后您可以访问:

SELECT arr[1] AS s1, arr[2] AS s2, arr[3] AS s3 --, ...
FROM (
    SELECT regexp_split_to_array(id2, '[:-]') AS arr
    FROM  (VALUES ('chr1:10000485-10006485@NM_022787@NMNAT1')) tbl(id2)
    ) sub;

s1      s2          s3
--------------------------------------------
chr1    10000485    10006485@NM_022787@NMNAT1

或者嵌套split_part() - 并按照评论中的要求将所有输入列添加到右侧:

SELECT split_part(id2, ':', 1) AS s1
      ,split_part(split_part(id2, ':', 2), '-', 1) AS s2
      ,split_part(split_part(id2, ':', 2), '-', 2) AS s3
      ,*
FROM  (VALUES ('chr1:10000485-10006485@NM_022787@NMNAT1')) tbl(id2);

相同的结果(加上所有输入列)。这实际上取决于您的字符串如何变化。

解释错误

您得到的错误是因为您只能引用 SELECT 列表中的 input 列,而不是 output 列。
您需要将查询包装在 子查询 中以引用输出列(在您的情况下为s2),或 repeat 基于输入列的表达式,如上所示。

【讨论】:

  • 更准确地说,我想创建一个查询,将新的 3 个拆分结合到原始表的最左侧。如果我根据一个字符拆分我的列,例如“:”,这将如下所示:select split_part(id2, ':', 1)s1,split_part(id2, ':', 2) s2, * from roynewtable我喜欢在这个查询中使用星号 (*),它允许我按原样输出我的整个原始表,而不实际表示每一列(我的表中有 15 列......)我可以在 2 上执行拆分吗不同的字符,仍然在我的 SELECT 中使用 * 以避免指定每一列?
  • @Roy:* 只是“所有输入列”的简写,可以在每个SELECT 中使用。这是 SQL 的基础。
  • 是的,当然(我知道)——但是,我没有确切的查询,我今晚早些时候已经厌倦了——但在某些时候我尝试了 SELECT *,而不是 SELECT 显式列 - 我已收到整个表格列 (= *) - 作为一列输出 (!)。意思是,整个表的列输出为一列,没有分隔......但是当我逐列指定时,我的输出恢复正常......如果我会尝试检索我的尝试向您展示找到它!....
  • 事实上 - 在考虑了所有优秀的 cmets 之后(谢谢大家!) - 我的最终和最简单的解决方案(我认为..)是:select split_part(s2, '- ', 1)s3,* from (select split_part(id2, ':', 1)s1,split_part(id2, ':', 2) s2, * from roynewtable)t2
  • 您意识到您的s2 由第二第三部分组成,对吗?至于“整行作为单列”:您可以通过SELECT t FROM roynewtable t 获得。它是复合行类型的文本表示。
猜你喜欢
  • 1970-01-01
  • 2020-06-18
  • 1970-01-01
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 2021-09-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多