我正在使用PostgreSQL 9.5,并且有一个带有" area_name"的表。具有编号扩展名的文本列:
area_name
----------------
AREA
AREA EXT
AREA EXT 1
AREA EXT 5
AREA EXT 49
AREA EXT 50
我想通过扩展数字命令结果,如上所示。
我尝试使用regexp_replace来将数字设为0,但使用长度为4的数字会在数字前加上2 0,无论是1还是2位数!
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
我在哪里使用替换表达式出错?
答案 0 :(得分:0)
<强>更新强>
(我在 AREA TEXT 509 中添加了一行
)看起来你无法引用&#39; \ 1&#39;从常规到lpad(
都是这样的。看下面 - 列o是你的 - 结果是 00509 ,第二列有长度(&#39; \ 1&#39;)*当然总是两个,因为'\1'
是解释为文本,而不是正则表达式元语法。所以我认为发生的事情是lpad
将第一个参数解释为metasyntax,但是从第二个参数中减去'\1'
的长度将其解释为 text =&gt; 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
答案 1 :(得分:0)
执行regexp_replace(area_name, ' EXT (\d*)', ' EXT ' || lpad('\1', 4, '0'))
时
首先评估参数
lpad('\1', 4, '0')
变为'00\1'
' EXT ' || lpad('\1', 4, '0')
变为' EXT 00\1'
这意味着捕获的组(本例中的数字)将以2个零开头。
您的目标可以分两个阶段实现 -
select area_name
,regexp_replace(regexp_replace(area_name,'\d+',repeat('0',4) || '\&'),'\d*(\d{4})','\1') 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 0001 |
+-------------+---------------+
| AREA EXT 5 | AREA EXT 0005 |
+-------------+---------------+
| AREA EXT 49 | AREA EXT 0049 |
+-------------+---------------+
| AREA EXT 50 | AREA EXT 0050 |
+-------------+---------------+
如果您的文字中包含多个号码,请使用此版本基于'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
;
答案 2 :(得分:0)
这是实现目标的另一种简单方法
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 |
+-------------+--------------+
答案 3 :(得分:0)
我不确定你为什么试图将它们格式化为你的问题要求订购。这很简单。只需将它们保留为int
。
我想通过扩展按数字顺序排序结果。
只需输入ORDER BY
声明。
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)