当完成指示器存在于多个实例中时,提取动态长度的字符串。 Postgres
Posted
技术标签:
【中文标题】当完成指示器存在于多个实例中时,提取动态长度的字符串。 Postgres【英文标题】:Extract string of dynamic length when the indicator of completion exists in multiple instances. Postgres 【发布时间】:2016-11-09 19:09:21 【问题描述】:所以如果我有一个 varchar 长度字符串列,让我们调用 ID(下面的示例):
97.128.39.256.1460854333288493
25.365.49.12.13454154815132
346.45.156.354.1523425161233
我想像 excel 中的左侧一样抓取 4th 句点左侧的所有内容。如何创建动态字符串来查找句点的第四个实例?
我知道子字符串是一个开始,但不确定如何写入存在的动态长度
【问题讨论】:
Greenplum 还是 Postgres?这有很大的不同。 Greenplum 基于非常旧的 Postgres 版本。 greenplum 不幸的是...-.- 幸运的是,您是指 Greenplum。 :) 【参考方案1】:这可能是其他人最容易阅读的:
select split_part(i, '.', 1) || '.' ||
split_part(i, '.', 2) || '.' ||
split_part(i, '.', 3) || '.' ||
split_part(i, '.', 4)
from (select '97.128.39.256.1460854333288493' as i) as sub;
或者如果你不喜欢 split_part 而更喜欢使用数组:
select array_to_string((string_to_array(i, '.'))[1:4], '.')
from (select '97.128.39.256.1460854333288493' as i) as sub;
我认为数组示例乍一看有点难以掌握,但两者都有效。
根据修改后的问题更新了答案,也将 Unix 时间戳转换为 Greenplum 时间戳:
select 'epoch'::timestamp + '1 second'::interval *
(split_part(i, '.', 5)::numeric/1000000) as event_time,
array_to_string((string_to_array(i, '.'))[1:4], '.') as ip_address
from (
select '97.128.39.256.1460854333288493' as i
) as sub;
【讨论】:
....谢谢乔恩。谢谢你,三重谢谢。你是男人。你是对的,阵列不是立即直观的,但它看起来更干净。我将阅读有关它的文档以了解有关此功能的更多信息。 嗨@Jon-roberts,一个简单的问题是,如果我试图将您的数组建议嵌入到已经定义了精度级别的语法中,我会收到一个错误“错误:类型的输入语法无效双精度”。有没有办法绕过它?我正在合并您的函数的示例: SELECT TO_TIMESTAMP(substring(i from char_length (length(array_to_string((string_to_array(i, '.'))[1:4], '.')))+2 for 10 )::float)::date as Date 97.128.39 无法从字符串转换为浮点数。这个字符串是否以某种方式表示日期格式?如果有,每个数字代表什么? 所以'i'的varchar字符串是元素的混合,其中第一部分是IP地址,第二部分是unix时间字符串,最后是另一个id。我正在使用您的数组来获取第一部分(IP),然后我应用长度函数来获取字符数,这样我就可以告诉子字符串我想要实际提取 unix 编号的起点。 to_timestamp 和 date 然后将该 unix 时间戳转换为可使用的日期。我应该使用其他方法吗?再次感谢您的跟进!【参考方案2】:你也可以试试这个:
mydb=> select regexp_replace('97.128.39.256.1460854333288493', E'^((?:\\d+\\.)3\\d+).+$', E'\\1');
regexp_replace
----------------
97.128.39.256
(1 row)
Time: 0.634 ms
【讨论】:
这只适用于直接值吗?当我尝试用列名替换字符串时,它没有改变 select regexp_replace(id, '^((?:\d+\.)3\d+).+$', '\1') regexp_replace从限制 3 很抱歉。那是在 PostgreSQL 上。在 GPDB 中运行它,它略有变化: gpadmin=# 选择 id, regexp_replace(id, E'^((?:\\d+\\.)3\\d+).+$', E'\\1' ) 从测试中复制;编号 |回复--------------------------------+---------------- 25.365.49.12.13454154815132 | 25.365.49.12 346.45.156.354.1523425161233 | 346.45.156.354 97.128.39.256.1460854333288493 | 97.128.39.256(3行)时间:22.550毫秒 :DD 谢谢!效果很好!!我真的需要了解这个正则表达式。非常感谢! 让我试着帮忙。 E'...' 只是说以下字符串包含转义字符。 '^' 表示“字符串的开头”;开头的 '(' 开始一个捕获组,稍后将由 '\\1' 引用,以提取在那个 '( ... )' 中匹配的所有内容;'(?:\\d+\\. )3' 是一个非捕获组,它有一个或多个数字后跟一个句点,并且重复 3 次;然后 '\\d+' 表示要捕获更多数字,然后 ')' 是结束你想抢的东西;最后,'.+$' 只是“剩下的,到最后”。【参考方案3】:with t (s) as ( values
('97.128.39.256.1460854333288493'),
('25.365.49.12.13454154815132'),
('346.45.156.354.1523425161233')
)
select a[1] || '.' || a[2] || '.' || a[3] || '.' || a[4]
from (
select regexp_split_to_array(s, '\.')
from t
) t (a)
;
?column?
----------------
97.128.39.256
25.365.49.12
346.45.156.354
【讨论】:
您好 Clodoaldo,感谢您的意见!第一部分的问题。我假设我根本无法使用 with t (id) 然后立即将此正则表达式拆分为数组项?或者如果我要拆分列名,我将如何使用正则表达式?如果我只是从 select a[1] 开始运行中间部分,我的输出是三个零。以上是关于当完成指示器存在于多个实例中时,提取动态长度的字符串。 Postgres的主要内容,如果未能解决你的问题,请参考以下文章
Python Dictionary交换键:值存在于多个键中时的值对[重复]
当元素存在于数组中时,为啥 index = -1? [复制]
Javascript:当元素存在于数组中时,为啥 indexOf 函数返回 -1?