今天在处理数据时遇到特殊情况,需要处理类似’大于等于2500,小于3000‘,’4400-4600‘的字段,需要将数字部分除以某个数值。这里用到了字符串分割函数。
regexp_split_to_array
regexp_split_to_array()函数可以将一个字符串通过正则表达式分隔成数组。如果没有匹配到正则表达式,则整个字符串会作为单元素数组返回。
SELECT regexp_split_to_array('4400-4600', '\D+')
-- {4400,4600}
SELECT regexp_split_to_array('大于等于2500,小于3000', '\D+')
-- {"",2500,3000}
这里可以发现,如果有汉字,数组里会存在一个空字符串。
出现空字符串是因为\D+匹配了字符串开头的非数字字符(即“大于等于”)。regexp_split_to_array函数会将匹配到的部分作为分隔符,并将分隔符两边的部分作为数组元素。由于字符串开头没有数字,所以在第一个匹配到的非数字字符之前会有一个空字符串。
这里我们使用array_remove()函数去掉数组中的空字符串,这样就可以使用数组分别获取两个数字的值
SELECT array_remove(regexp_split_to_array('大于等于2500,小于3000', '\D+'), '')
-- {2500,3000}
SELECT (array_remove(regexp_split_to_array('大于等于2500,小于3000', '\D+'), ''))[1]
-- 2500
SELECT (array_remove(regexp_split_to_array('大于等于2500,小于3000', '\D+'), ''))[1]
-- 3000
应用场景:
这里我已知热值或者热值范围,需要使用单价计算单卡价格,这里需要注意的是,如果只有大于或者小于,不是区间,算出价格以后需要将大于换成小于,小于换成大于,区间数据需要将后面的值放到前面。数据如下图

实现的代码如下:
-- 这里热值从两个地方获取,cl.qnetar为空的时候,使用agree_standard_value,且只有cl.qnetar存在区间数据,agree_standard_value是纯数字
CASE WHEN cl.qnetar = '' OR cl.qnetar IS NULL
-- 除0判断
THEN CASE WHEN rd.agree_standard_value IS NULL OR rd.agree_standard_value::INT = 0
THEN '0' ELSE ROUND(cl.price/rd.agree_standard_value, 4)::TEXT END
WHEN
-- 将大于替换小于
(array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[2] IS NULL AND LEFT(cl.qnetar, 1) = '大'
THEN
REPLACE(
REPLACE(
cl.qnetar,
(array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1],
ROUND(CASE WHEN (array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1] IS NULL OR (array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1] = '' OR (array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1]::INT = 0 THEN '0' ELSE cl.price/(array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1]::NUMERIC END, 4)::TEXT),
'大',
'小')
when (array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[2] IS NULL
THEN
-- 将小于替换大于
REPLACE(
REPLACE(
cl.qnetar,
(array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1],
ROUND(CASE WHEN (array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1] IS NULL OR (array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1] = '' OR (array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1]::INT = 0 THEN '0' ELSE cl.price/(array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1]::NUMERIC END, 4)::TEXT),
'小',
'大')
ELSE
REPLACE(
REPLACE(
-- 正常区间的字符串替换,这里需要注意,要将第二个值放在前面,第一个值放在后面
cl.qnetar,
(array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1],
ROUND(CASE WHEN (array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[2] IS NULL OR (array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[2] = '' OR (array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[2]::INT = 0 THEN '0' ELSE cl.price/(array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[2]::NUMERIC END, 4)::TEXT),
(array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[2],
ROUND(CASE WHEN (array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1] IS NULL OR (array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1] = '' OR (array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1]::INT = 0 THEN '0' ELSE cl.price/(array_remove(regexp_split_to_array(cl.qnetar, '\D+'), ''))[1]::NUMERIC END, 4)::TEXT)
END kcal_price,
split_part()
split_part() 函数可以根据指定的分隔符来分割字符串。它接受三个参数:要分割的字符串,分隔符和返回部分的位置(基于索引的)。
SELECT split_part('4400-4600', '-', 2)
-- 4600
SELECT split_part('4400-4600', '-', 1)
-- 4400
regexp_split_to_table()
regexp_split_to_table() 功能类似于 regexp_split_to_array(),不过这个函数会将分割结果直接展开成一张表。
SELECT regexp_split_to_table('4400-4600', '\D+')
-------------------------
-- regexp_split_to_table
-- 4400
-- 4600
