正则表达式从 postgresql 中的时间戳字符串中间删除“-”
Posted
技术标签:
【中文标题】正则表达式从 postgresql 中的时间戳字符串中间删除“-”【英文标题】:Regex to remove "-" from the middle of a timestamp string in postgresql 【发布时间】:2014-12-09 15:16:54 【问题描述】:我有一个表格,其中包含 hour
列的 timestamp
格式不正确:
hour
---------------------
2014-12-06-01:44:35
2014-12-06-01:44:35
2014-12-06-01:44:35
2014-12-06-01:44:35
2014-12-06-01:44:35
2014-12-06-01:44:35
我想在中间用' '
替换-
,所以它看起来像这样:
hour
---------------------
2014-12-06 01:44:35
2014-12-06 01:44:35
2014-12-06 01:44:35
2014-12-06 01:44:35
2014-12-06 01:44:35
2014-12-06 01:44:35
我试过了:
select regexp_replace(hour, '\d4-\d2-\d2(-)\d2:\d2:\d2', ' ')
from my_table;
但不幸的是,它没有任何区别。 我使用的是 Redshift,而不是 PostgreSQL。
【问题讨论】:
【参考方案1】:在 postgresql 中创建 Regex 表达式时需要考虑一些事项。首先,您需要转义反斜杠。所以你需要\\
,而不是\
。其次,您可以通过使用 \n 在括号中捕获第 n 个组来引用捕获组。您可以在替换值中使用捕获组来引用原始字符串的部分内容。
将所有这些放在一起,这就是您所需要的:
regexp_replace('hour', '(\\d4-\\d2-\\d2)-(\\d2:\\d2:\\d2)', '\\1 \\2')
【讨论】:
【参考方案2】:Redshift 中的有限选项
regexp_replace(hour, '(^\\d4-\\d2-\\d2)-(\\d2:\\d2:\\d2$)', '\\1 \\2') AS a
regexp_replace(hour, '(^\\d4-\\d\\d-\\d\\d)-(\\d\\d:\\d\\d:\\d\\d)$', '\\1 \\2') AS b
regexp_replace(hour, '(^[\\d-]10)-([\\d:]+)$', '\\1 \\2') AS c
left(hour,10) || ' ' || substring(hour FROM 12) AS e
现代 Postgres (9.1+) 中的更多选项
regexp_replace(hour, '(^\d4-\d2-\d2)-(\d2:\d2:\d2$)', '\1 \2') AS a
regexp_replace(hour, '(^\d4-\d\d-\d\d)-(\d\d:\d\d:\d\d)$', '\1 \2') AS b
regexp_replace(hour, '(^[\d-]10)-([\d:]+)$', '\1 \2') AS c
reverse(regexp_replace(reverse(hour), '-', ' ')) AS d
left(hour,10) || ' ' || right(hour, -11) AS e
overlay(hour placing ' ' from 11) AS f
to_timestamp(hour, 'YYYY-MM-DD-HH24:MI:SS') AS ts
SQL Fiddle.
按出现顺序从“限制性”到“廉价”。 ts
很特别。
一个
这就像currently accepted answer by @Zeki,在开头和结尾都加上了锚点^
和$
,以使其更加不模糊并且可能更快。
您希望 \d
的特殊含义为 class shorthand 用于数字。
在 Postgres 中,不要使用 \\
转义反斜杠 \
。除非您使用早已过时的非默认设置 standard_conforming_strings = off
运行,否则这是不正确的。
Redshift 卡在了一个旧的开发阶段,就是这样做的。除非用另一个反斜杠转义,否则反斜杠会被解释。
b
\d\d
比\d2
更短更便宜。
c
使用字符类进行简化:数字 + 连字符:[\d-]
和数字 + 冒号:[\d:]
。
d
由于regexp_replace()
没有第4个参数'g'
只替换第一个匹配,你可以reverse()
字符串,替换第一个连字符和reverse()
后面。
在 Redshift 中不起作用,因为它使用 总是 替换所有出现的 simpler version of regexp_replace()
。
e
如果格式固定如图所示,只需取前 10 个字符、一个空格和字符串的其余部分。
Redshift 使用不接受负参数的simpler versions of left()
and right()
,所以我用substring()
代替。
f
或者,更简单一点,只是 overlay() 第 11 个字符加一个空格。Not implemented in Redshift.
ts
与其他类型不同,to_timestamp()
返回正确的 timestamp with time zone
类型,而不是 text
。您也可以将结果分配给timestamp without time zone
。 Details.。如果你想转换你的字符串,到目前为止最好的选择。
Not implemented in Redshift.
【讨论】:
不幸的是,没有一个问题给了我正确的答案。前 3 个(a
、b
、c
)根本没有改变结果。 4'th (d
) - 删除了所有的-
,所以时间戳看起来像这样2014 12 06 01:44:35
。第 5 次 (e
) 返回错误 context: Negative value given!
。最后一个(f
)返回,它不存在:function pg_catalog.overlay(character varying, "unknown", integer) does not exist
。
@Vor:嗯,抱歉,Redshift 有更多限制。正如您在小提琴中看到的那样,这一切都适用于现代 Postgres。我为 Redshift 和解释添加了一些工作版本。
非常感谢您的详细解答【参考方案3】:
(\d4-\d2-\d2)-(\d2:\d2:\d2)
试试这个。替换为$1 $2
。查看演示。
https://regex101.com/r/iY3eK8/13
【讨论】:
他们的输出正是我想要的。但是你能指导我在我的 sql 命令中改变什么(在正则表达式部分旁边) @Vor 在正则表达式旁边更改替换字符串。$1 $2
或 \1 \2
我尝试过regexp_replace(hour, '(\d4-\d2-\d2)-(\d2:\d2:\d2)', '\1 \2')
和regexp_replace(hour, '(\d4-\d2-\d2)-(\d2:\d2:\d2)', '$1 $2')
,但仍然没有给我正确的结果。
非常感谢您的帮助,您的回答是正确的,但就像@Zeki 建议的那样,我不得不转义它的反斜杠。以上是关于正则表达式从 postgresql 中的时间戳字符串中间删除“-”的主要内容,如果未能解决你的问题,请参考以下文章