Postgresql 在regexp\u replace中使用lpad
我使用的是PostgreSQL 9.5,表中有一个“area_name”文本列,其中包含编号的扩展名:Postgresql 在regexp\u replace中使用lpad,postgresql,Postgresql,我使用的是PostgreSQL 9.5,表中有一个“area_name”文本列,其中包含编号的扩展名: area_name ---------------- AREA AREA EXT AREA EXT 1 AREA EXT 5 AREA EXT 49 AREA EXT 50 我想对结果进行数字排序,如上图所示 我曾尝试使用regexp_replace将数字lpad为0,但使用长度为4时,无论数字是1位还是2位,都会在数字前面加上20 create table ext_test ( a
area_name
----------------
AREA
AREA EXT
AREA EXT 1
AREA EXT 5
AREA EXT 49
AREA EXT 50
我想对结果进行数字排序,如上图所示
我曾尝试使用regexp_replace将数字lpad为0,但使用长度为4时,无论数字是1位还是2位,都会在数字前面加上20
create table ext_test (
area_name text
);
insert into ext_test values
('AREA'),
('AREA EXT'),
('AREA EXT 1'),
('AREA EXT 5'),
('AREA EXT 49'),
('AREA EXT 50');
select
area_name,
regexp_replace(area_name, ' EXT (\d*)', ' EXT ' || lpad('\1', 4, '0')) as order_result
from ext_test
order by order_result;
area_name | order_result
------------------------------
AREA | AREA
AREA EXT | AREA EXT
AREA EXT 1 | AREA EXT 001
AREA EXT 49 | AREA EXT 0049
AREA EXT 5 | AREA EXT 005
AREA EXT 50 | AREA EXT 0050
替换表达式哪里出了问题?更新: (我又添加了一行区域文本509) 看起来您不能像这样将“\1”从常规引用到
lpad(
)。请看下面-o列是您的-结果是00509,第二列有长度(“\1”)*这当然总是两个,因为'\1'
被解释为文本,而不是正则表达式元语法。所以我相信发生的事情是lpad
将第一个参数解释为元语法,但从第二个参数中减去'\1'
的长度将其解释为文本=>4-2始终是2。因此它在任何输入
虽然这可能是错误,也可能不是SQL函数与正则表达式元语法的混合使用,但我建议从正则表达式中获取一个值,然后将其与SQL函数一起使用。这里的r列是示例。而replace列是平均输出的示例:
t=# with p as (select regexp_replace(area_name, ' EXT (\d*)', ' EXT ' || lpad('\1', 4, '0')) o,regexp_replace(area_name,'AREA EXT (\d*)',length('\1')||'.\1'||'.'), area_name,regexp_replace(area_name,'AREA EXT (\d*)','\1') r from ext_test)
select *, length(r),replace(area_name,r,lpad(r,4,'0')) from p;
o | regexp_replace | area_name | r | length | replace
----------------+----------------+--------------+----------+--------+---------------
AREA | AREA | AREA | AREA | 4 | AREA
AREA EXT | AREA EXT | AREA EXT | AREA EXT | 8 | AREA
AREA EXT 001 | 2.1. | AREA EXT 1 | 1 | 1 | AREA EXT 0001
AREA EXT 005 | 2.5. | AREA EXT 5 | 5 | 1 | AREA EXT 0005
AREA EXT 0049 | 2.49. | AREA EXT 49 | 49 | 2 | AREA EXT 0049
AREA EXT 0050 | 2.50. | AREA EXT 50 | 50 | 2 | AREA EXT 0050
AREA EXT 00509 | 2.509. | AREA EXT 509 | 509 | 3 | AREA EXT 0509
(7 rows)
Time: 0.519 ms
只是一个建议-可能使用整数进行排序,如这里所示:
t=# with a as (select *,split_part(area_name,'AREA EXT ',2) s from ext_test) select area_name,case when s='' then 0 else s::int end c from a order by c,area_name;
area_name | c
-------------+----
AREA | 0
AREA EXT | 0
AREA EXT 1 | 1
AREA EXT 5 | 5
AREA EXT 49 | 49
AREA EXT 50 | 50
(6 rows)
Time: 0.354 ms
执行
regexp\u replace(区域名称,'EXT(\d*),'EXT'| | lpad('\1',4,'0'))时
首先,正在评估所有参数
lpad('\1',4',0')
变成'00\1'
'EXT'| | lpad('\1',4',0')
变为'EXT 00\1'
这意味着捕获的组(本例中的数字)前面将有2个零
你的目标可以分两个阶段实现-
如果您的文本中有多个数字,请使用基于
'AREA EXT'
-
select area_name
,regexp_replace(regexp_replace(area_name,'(?<=AREA EXT )\d+',repeat('0',4) || '\&'),'(?<=AREA EXT )\d*(\d{4})','\1') as order_result
from ext_test
order by order_result
;
选择区域名称
,regexp_replace(regexp_replace)(区域名称),(?这里是实现目标的另一种简单方法
select area_name
,substring (area_name,'(?<=AREA EXT )\d+')::int as order_result
from ext_test
order by order_result nulls first
,area_name
;
我不知道你为什么要尝试将你的问题调用格式化以便排序。这很简单。只需将它们保留为int
我想按如上所示的扩展对结果进行数字排序。
只需输入orderby
语句
SELECT area_name
FROM ext_test
ORDER BY
CASE
WHEN area_name ~ '\d'
THEN (regexp_matches(area_name, '\d+'))[1]::int
END NULLS FIRST,
area_name;
area_name
-------------
AREA
AREA EXT
AREA EXT 1
AREA EXT 5
AREA EXT 49
AREA EXT 50
(6 rows)
这是一个简化的示例。在上面的实际数据“区域”中,有数千条记录中的数百个不同名称。有时where子句在名称的开头进行选择,然后我可以使用:按长度排序(区域名称),area_name
Where my Where子句变得更复杂,结果中可能有多个area_名称,因此这不起作用。请用更多示例更新您的问题?这些数据足以说明问题。真正的问题是,为什么在regexp_replace中填充没有按预期工作?我不知道如何引起注意关于这些特殊的人。像Erwin或Craig这样的鲸鱼可以回答这是否是一个bug,或者你只是不想使用常规的元语法作为SQL函数的参数谢谢。现在我明白了为什么我没有得到我期望的结果。我希望你看看我的答案。;)它更简单、更快。
select area_name
,substring (area_name,'(?<=AREA EXT )\d+')::int as order_result
from ext_test
order by order_result nulls first
,area_name
;
+-------------+--------------+
| area_name | order_result |
+-------------+--------------+
| AREA | (null) |
+-------------+--------------+
| AREA EXT | (null) |
+-------------+--------------+
| AREA EXT 1 | 1 |
+-------------+--------------+
| AREA EXT 5 | 5 |
+-------------+--------------+
| AREA EXT 49 | 49 |
+-------------+--------------+
| AREA EXT 50 | 50 |
+-------------+--------------+
SELECT area_name
FROM ext_test
ORDER BY
CASE
WHEN area_name ~ '\d'
THEN (regexp_matches(area_name, '\d+'))[1]::int
END NULLS FIRST,
area_name;
area_name
-------------
AREA
AREA EXT
AREA EXT 1
AREA EXT 5
AREA EXT 49
AREA EXT 50
(6 rows)