我可以在 Firebird POSITION 函数中使用通配符吗
Posted
技术标签:
【中文标题】我可以在 Firebird POSITION 函数中使用通配符吗【英文标题】:Can I use wildcards in Firebird POSITION function 【发布时间】:2020-07-10 07:16:14 【问题描述】:我使用的是 Firebird 2.1。
我的工作订单号可能有 1 或 2 个字母字符,然后是 4 或 5 个数字,然后可能是带有 1 个字母字符和 2 个数字的前缀。
我想提取中间的 4-5 位数字。
我尝试了以下方法来查找数字字符,但它返回 0:
POSITION('%[0-9]%',JOBHEADER.ORDERNUMBER,1) AS "FIRST NUMBER"
我不确定是否可以在POSITION
函数中使用通配符。我想我可以尝试检查数字的第二个或第三个字符,但我真的需要通配符功能,然后在找到第一个数字的位置后找到下一个字母。或者也许有另一种解决方案来提取数字。
我发现了类似的东西:
CASE WHEN SUBSTRING(ordernumber FROM 2 FOR 5) SIMILAR TO '[0-9]+'
THEN SUBSTRING(ordernumber FROM 2 FOR 5)
ELSE SUBSTRING(ordernumber FROM 3 FOR 5)
END as PROJECTNUMBER
但是数字可能从前 5 个字符开始,然后 if/case 语句开始变得非常大。
【问题讨论】:
then maybe a prefix with 1 alpha character
- “then” 表示“之后”,前缀是 before 主要值,而不是之后。之后的那些通常作为 POSTfixes。所以,请给出示例输入和输出数据。 // 就个人而言,为了解析,我会写一个存储过程
【参考方案1】:
不,您不能使用 POSITION
执行此操作。位置搜索给定字符串中的确切子字符串。但是,在 Firebird 3 中,您可以使用 SUBSTRING
和正则表达式来提取值,例如:
substring(ordernumber similar '%#"[[:DIGIT:]]+#"%' escape '#')
正则表达式必须覆盖整个字符串,而#"
包含要提取的术语(#
是明确定义的转义符号)。您可能需要使用更复杂的模式,例如 [^[:DIGIT:]]*#"[[:DIGIT:]]+#"([^[:DIGIT:]]%)?
,以避免出现贪婪的极端情况。
如果您知道模式始终是 1 或 2 个 alpha、4 或 5 个要提取的数字,可能后跟 1 个 alpha 和 2 个数字,您也可以使用 [[:ALPHA:]]1,2#"[[:DIGIT:]]4,5#"([[:ALPHA:]][[:DIGIT:]]1,2)?
。如果模式不匹配,则返回null
。
另见:
README.substring_similar.txt regular expression syntax请注意,Firebird 支持的 SQL 标准正则表达式语法有点奇怪,并且不如其他语言中常见的正则表达式强大。
使用 PSQL
要使用 PSQL 解决这个问题,在 Firebird 2.1 下,您可以使用类似:
create or alter procedure extract_number(input_value varchar(50))
returns (output_value bigint)
as
declare char_position integer = 0;
declare number_string varchar(20) = '';
declare current_char char(1);
begin
while (char_position < char_length(input_value)) do
begin
char_position = char_position + 1;
current_char = substring(input_value from char_position for 1);
if ('0' <= current_char and current_char <= '9') then
begin
number_string = number_string || current_char;
end
else if (char_length(number_string) > 0) then
begin
-- switching from numeric to non-numeric, found first number occurrence in string
leave;
end
end
output_value = iif(char_length(number_string) > 0, cast(number_string as bigint), null);
end
【讨论】:
问题是,他明确提到了 FB 2.1 而不是 3+ // 然而,这导致了问题到底是什么问题以及究竟有什么资格获得答案... @Arioch'The 问题的直接答案(即“我可以在 Firebird POSITION 函数中使用通配符”)是 “不,你不能这样做这是POSITION
。”。答案的其余部分提供了 Firebird 3 上可用的替代方案。
@MarkRotteveel 我可以编写一个触发器,它会使用 WHILE 循环遍历作业编号字符串中的每个字符以找到第一个数字,然后将其添加到变量并继续直到出现非数字字符到达。然后将该变量分配给一个字段?这将达到相同的最终结果。但不是试图通过 select 语句获取数字,而是在将数据输入表时得到它。
其实这和@Arioch'The 在他对我的问题的评论中提到的类似,但是由于我从来没有写过程序,那么触发器对我来说可能是一个更好的解决方案。
@SimonKing 是的,这是可以做到的。有时间我会看看是否可以添加一个这样做的示例。以上是关于我可以在 Firebird POSITION 函数中使用通配符吗的主要内容,如果未能解决你的问题,请参考以下文章