如何在第 n 次出现的定界符之前剪切 varchar/text?数据库

How to cut varchar/text before n'th occurence of delimiter? PostgreSQL

我有字符串(在数据库中保存为 varchar),我必须在第 n 个定界符出现之前剪切它们。

示例输入:

String: 'My-Example-Awesome-String'
Delimiter: '-'
Occurence: 2

输出:

My-Example

我为快速原型实现了这个功能:

CREATE OR REPLACE FUNCTION find_position_delimiter(fulltext varchar, delimiter varchar, occurence integer)
  RETURNS varchar AS
$BODY$

DECLARE
    result varchar = '';
    arr text[] = regexp_split_to_array( fulltext, delimiter);
    word text;
    counter integer := 0;

BEGIN
    FOREACH word IN ARRAY arr LOOP
        EXIT WHEN ( counter = occurence  );
        IF (counter > 0) THEN result := result || delimiter;
        END IF;
            result := result || word;
            counter := counter + 1;
    END LOOP;
    RETURN result;
END;


$BODY$
LANGUAGE 'plpgsql' IMMUTABLE;
SELECT find_position_delimiter('My-Example-Awesome-String', '-', 2);

现在假设字符串不为空(由我将调用函数的查询提供)并且定界符字符串至少包含所提供模式的一个定界符。

但是现在我需要更好的东西来进行性能测试。如果可能的话,我希望看到最通用的解决方案,因为并不是我系统的每个用户都在使用 PostgreSQL 数据库(他们中很少有人喜欢 Oracle、MySQL 或 SQLite),但这不是最重要的.但性能是 - 因为在特定搜索中,该函数甚至可以调用数百次。

我没有找到任何关于快速简便地使用 varchar 作为字符的 table 并检查定界符出现的任何信息(我记得出现的位置,然后创建从第一个字符到第 n 个字符的子字符串定界符位置-1)。有任何想法吗?是更智能的解决方案吗?

@ 编辑:是的,我知道每个数据库中的功能都会有所不同,但功能主体可能非常相似或相同。通用性不是主要目标 :) 对于那个糟糕的函数工作名称感到抱歉,我只是看到它没有正确的含义。

create or replace function trunc(string text, delimiter char, occurence int) returns text as $$
return delimiter.join(string.split(delimiter)[:occurence])
$$ language plpythonu;

# select trunc('My-Example-Awesome-String', '-', 2);
   trunc    
------------
 My-Example
(1 row)

你可以尝试做一些基于此的事情:

select 
  varcharColumnName,
  INSTR(varcharColumnName,'-',1,2),
  case when INSTR(varcharColumnName,'-',1,2) <> 0
    THEN SUBSTR(varcharColumnName, 1, INSTR(varcharColumnName,'-',1,2) - 1)
    else '...'
  end
from tableName;

当然,您必须按照自己的方式处理 "else"。它适用于 postgres 和 oracle(已测试),它应该适用于其他 dbms,因为这些是标准 sql 函数

//edit - 作为一个函数,但是这样很难让它跨数据库

CREATE OR REPLACE FUNCTION find_position_delimiter(fulltext varchar, delimiter varchar, occurence integer) 
RETURNS varchar as
$BODY$

DECLARE
    result varchar := '';
    delimiterPos integer := 0;

BEGIN
    delimiterPos := INSTR(fulltext,delimiter,1,occurence);
    result := SUBSTR(fulltext, 1, delimiterPos - 1);
    RETURN result;
END;


$BODY$
LANGUAGE 'plpgsql' IMMUTABLE;
SELECT find_position_delimiter('My-Example-Awesome-String', '-', 2);