模仿MySQL';PGSQL中的s子字符串_index()

模仿MySQL';PGSQL中的s子字符串_index(),mysql,sql,postgresql,Mysql,Sql,Postgresql,我想找到一种优雅的方式来模仿Postgres中MySQL函数的行为 在MySQL中,它非常简单: mysql> create temporary table test1(test varchar(200)); Query OK, 0 rows affected (0.01 sec) mysql> insert into test1 values('apples||oranges'),('apples||grapes'); Query OK, 2 rows affected (0.0

我想找到一种优雅的方式来模仿Postgres中MySQL函数的行为

在MySQL中,它非常简单:

mysql> create temporary table test1(test varchar(200));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test1 values('apples||oranges'),('apples||grapes');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from test1;
+-----------------+
| test            |
+-----------------+
| apples||oranges |
| apples||grapes  |
+-----------------+
2 rows in set (0.00 sec)

mysql> select substring_index(test, '||', 1) as field1, substring_index(test, '||', -1) as field2 from test1;
+--------+---------+
| field1 | field2  |
+--------+---------+
| apples | oranges |
| apples | grapes  |
+--------+---------+
2 rows in set (0.00 sec)
但我目前在PGSQL方面的工作相当糟糕:

hoth=# create temporary table test1(test text);
CREATE TABLE

hoth=# insert into test1 values('apples||oranges'),('apples||grapes');
INSERT 0 2

hoth=# select * from test1;
      test       
-----------------
 apples||oranges
 apples||grapes
(2 rows)

hoth=# select substring(test, 0, position('||' in test)) as field1,  substring(test, position('||' in test) + 2, char_length(test)) as field2  from test1;
 field1 | field2  
--------+---------
 apples | oranges
 apples | grapes
(2 rows)

也许有一个更优雅的解决方案,使用正则表达式,或者甚至可以将字符串拆分为变量中的数组,这可能会减少开销,如果字符串来自子查询或其他什么,我欢迎任何建议。

总是花时间浏览手册

如果拆分部分(字符串文本、分隔符文本、字段int)不符合您的要求(如果我理解您的MySQL函数,还需要更多),那么您需要解释其中的位置和原因。

以下是我如何在PostgreSQL中实现(或模拟)MySQL的子字符串索引()

CREATE OR REPLACE FUNCTION public.substring_index (
  str text,
  delim text,
  count integer = 1,
  out substring_index text
)
RETURNS text AS
$body$
BEGIN
  IF count > 0 THEN
    substring_index = array_to_string((string_to_array(str, delim))[:count], delim);
  ELSE
    DECLARE
      _array TEXT[];
    BEGIN
      _array = string_to_array(str, delim);
      substring_index = array_to_string(_array[array_length(_array, 1) + count + 1:], delim);    
    END;  
  END IF;
END;
$body$
LANGUAGE 'plpgsql'
IMMUTABLE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 5;
下面是mysql文档中的示例

postgres=# SELECT substring_index('www.mysql.com', '.', 2);
 substring_index
-----------------
 www.mysql
(1 row)

postgres=# SELECT substring_index('www.mysql.com', '.', -2);
 substring_index
-----------------
 mysql.com
(1 row)

我认为,开箱即用的解决方案是以更适合您要执行的查询的方式存储数据(例如,通过对数据进行归一化或使用数组类型)。我意识到这并不总是一个选项,但我想我会把它扔出去,特别是当你的MySQL示例被专门编码为正好分成两部分时。啊,手册似乎将“字符串函数和运算符”与“其他字符串函数”分开,这是我显然忽略的后者。谢谢。@jesse_galley:[强调我的]。因此,第一个列表旨在涵盖SQL标准指定的函数,而第二个列表旨在涵盖PostgreSQL扩展。虽然SPLIT_PART解决了上述示例,但它不是模拟MySQL子字符串索引的工具,给定子字符串,索引将子字符串返回到分隔符的指定出现次数的左侧或右侧。当遇到任意数量的分隔符时,如何模拟其行为?例如,从URL的较大部分选择域;e、 g:从“sports.adventures.Habiods.domain.com”和“pets.domain.com”中选择“domain.com”?为了在PostgreSQL中解决这个问题,我们可能需要reg表达式或组合各种字符串函数。另一个原因是拆分部分不能完全替换子字符串索引:字段必须大于零。MySQL允许从字符串末端相对分割负值。