如何在没有#39;出现分隔符之前剪切varchar / text? PostgreSQL的

时间:2015-03-11 09:00:09

标签: sql postgresql split delimiter cut

我有字符串(在数据库中保存为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作为chars表并检查分隔符出现的快速和简单的事情(我可以​​记住出现的位置,然后从第一个字符到第n个分隔符位置创建子字符串-1)。有任何想法吗?是更智能的解决方案吗?

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

2 个答案:

答案 0 :(得分: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)

答案 1 :(得分:1)

你可以尝试基于此做点什么:

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;

当然,你必须以你想要的方式处理“其他”。它适用于postgres和oracle(已测试),它应该适用于其他dbms,因为它们是标准的sql函数

//编辑 - 作为一个函数,但是这样很难使它成为跨dbms

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);