在PostgreSQL中提取分割字符串的最后部分的最有效方法是什么?

问题描述

我想在Postgresql函数提取完全限定域的子域,直到第二级。

目前,我有以下片段可以工作,但是我不确定这是否是最有效的方法

subdomains := left(query,length(query) - length(tld));
RETURN reverse(split_part(reverse(subdomains),'.',1)) || tld;

保证querytld子字符串结尾。

示例:

+---------------------+---------+---------------+
|        query        |   tld   |    output     |
+---------------------+---------+---------------+
| abc.example.com     | .com    | example.com   |
| x.y.z.example.co.uk | .co.uk  | example.co.uk |
| zzz.123.yyy.com.br  | .com.br | yyy.com.br    |
+---------------------+---------+---------------+

解决方法

这个效率也不是很高,但是至少reverse两次都不是,我猜array_length很便宜,而string_to_array的价格却和split_part差不多。这可能是错误的,但值得尝试。

sd_arr := string_to_array(subdomains,'.');
RETURN sd_arr[array_length(sd_arr,1)] || tld;

不使用变量分配要好得多:

RETURN (select arr[array_length(arr,1)] from (select string_to_array(subdomains,'.') as arr) t) || tld; 
,

不确定这是否更有效,但您可以将其与您的实现进行比较:

create or replace function get_domain(p_input text,p_tld text)
  returns text
as
$$
declare
  l_tld text[];
  l_items text[];
begin 
  l_tld := string_to_array(trim('.' from p_tld),'.');
  l_items := string_to_array(trim('.' from p_input),'.');
  return array_to_string(l_items[cardinality(l_items) - cardinality(l_tld):],'.'); 
end
$$
language plpgsql
immutable;

它本质上将输入域和顶级域转换为数组(对任何前导.进行剥离以避免空数组元素。

然后,通过从输入的长度中减去tld的长度(=元素数)来计算要返回的起始元素。因此,对于输入x.y.z.example.co.uk,它是6-2,这意味着它将返回从第4个元素开始的所有内容,然后将其转换回为“点分”表示法。

Online example