求助:PostgreSQL的substring函数在位置为0或负值时的行为解析
嘿,作为PostgreSQL新手遇到这个问题太正常了,毕竟它的substring位置计数规则和不少编程语言不一样,我来给你拆解清楚:
首先得记住一个核心规则:PostgreSQL里字符串的位置是从1开始计数的——第一个字符的位置是1,第二个是2,以此类推,这和Python、JavaScript这类从0开始的语言完全不同,这也是你困惑的根源。
接下来分别看你遇到的两种特殊情况:
1. 位置参数为0:substring('123456',0,1)返回空
当你把起始位置start设为0时,相当于指定了第一个字符之前的位置(毕竟第一个字符在位置1)。这时候你要截取1个字符,但这个位置本身并不指向任何有效字符,截取范围也无法覆盖到字符串的有效区间,所以PostgreSQL会直接返回空值。
简单说:0是一个“不存在有效字符”的虚拟位置,从这里开始自然拿不到任何内容。
2. 位置参数为负数:substring('123456',-1,2)返回空
负数的start参数是从字符串的末尾开始倒着计数的:比如start=-1指向最后一个字符('6'),start=-2指向倒数第二个字符('5'),以此类推。
但这里有个关键限制:如果start指定的位置加上要截取的长度,最终无法落在字符串的有效范围内(要么小于1,要么超出字符串总长度),就会返回空值。
你的例子里substring('123456',-1,2),start=-1指向最后一个字符(位置6),但你要求截取2个字符,而从位置6往后已经没有更多字符了。PostgreSQL判断无法满足截取2个字符的要求,所以返回空值。你可以试试把count改成1,就能得到预期的'6':
select substring('123456',-1,1); -- 返回 '6'
另外,如果负数的start本身就超出了字符串的开头,比如substring('123456',-7,2),因为字符串只有6个字符,倒数第7位已经在第一个字符之前了,同样会返回空值。
最后总结一下规则:
- 字符串位置从1开始,0和小于1的位置(包括负数导致的超出开头)都属于无效起始位置,无法截取到内容
- 负数位置要结合截取长度看是否能覆盖有效字符区间,否则返回空
内容的提问来源于stack exchange,提问作者ziMtyth

