当完成指示器存在于多个实例中时,提取动态长度的字符串。 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?

仅当文件存在于 shell 脚本中时才移动

当消息存在于 SQS 队列中时触发 AWS 中的 Lambda 函数

仅当用户存在于 Firebase 中时 Flutter google 登录?