PostgreSQL如何组合regex_split_to_array和foreach循环

时间:2017-09-20 14:15:31

标签: sql arrays postgresql foreach postgresql-9.1

我有一个包含多个逗号分隔值的列(最多50个国家/地区名称)。必须用另一个表中的特定代码(国家代码,ISO3)替换这些值。

互联网搜索让我将值拆分为数组(regex_split_to_array)并在数组中使用循环(FOREACH LOOP

我得到了一般概念,但我至少在语法方面苦苦挣扎(pqsl初学者)。

方法

DO
$do$
DECLARE
m   varchar[];
arr varchar[]; -- declare array
BEGIN
-- split the comma-separeted values to array and insert into the array
SELECT (regexp_split_to_array(country, E','))
  into arr
FROM tablename
WHERE xy;
FOREACH m SLICE 1 IN ARRAY arr
LOOP
-- update/replace the value with a function
RAISE NOTICE 'another function(%)', m;
END LOOP;

END
$do$

我认为填充阵列不会那样工作..

PostgreSQL 9.1

1 个答案:

答案 0 :(得分:1)

你不需要循环或PL / pgSQL。您可以使用一个语句执行此操作:

假设以下设置:

create table  tablename
(
  id integer primary key,
  country_list text
);

create table lookup
(
  iso_code varchar(3),
  country text
);

insert into tablename
values
(1, 'Germany, Austria, Italy'),
(2, 'Austria, France'),
(3, 'France, Switzerland');

insert into lookup
values
('de', 'Germany'),
('at', 'Austria'),
('it', 'Italy'),
('fr', 'France'),
('ch', 'Switzerland');

您可以使用以下国家/地区取消选择:

select s.id, trim(unnest(string_to_array(s.country_list, ','))) as country
from tablename s;

鉴于上面的示例数据,将返回以下内容:

id | country    
---+------------
 1 | Germany    
 1 | Austria    
 1 | Italy      
 2 | Austria    
 2 | France     
 3 | France     
 3 | Switzerland

这可以加入您的查找表:

with normalized as (
   select s.id, trim(unnest(string_to_array(s.country_list, ','))) as country
   from tablename s
)
select n.id, n.country, l.iso_code
from normalized n
  join lookup l on l.country = n.country;

返回以下内容:

id | country     | iso_code
---+-------------+---------
 1 | Austria     | at      
 1 | Germany     | de      
 1 | Italy       | it      
 2 | Austria     | at      
 2 | France      | fr      
 3 | France      | fr      
 3 | Switzerland | ch      

您可以将ISO代码列表聚合回您的非规范化结构:

with normalized as (
   select s.id, trim(unnest(string_to_array(s.country_list, ','))) as country
   from tablename s
)
select n.id, string_agg(l.iso_code,',') as iso_list
from normalized n
  join lookup l on l.country = n.country
group by n.id;

这可以用来替换目标表中的值:

with normalized as (
   select s.id, trim(unnest(string_to_array(s.country_list, ','))) as country
   from tablename s
), translated as (
  select n.id, string_agg(l.iso_code,',') as iso_list
  from normalized n
    join lookup l on l.country = n.country
  group by n.id
)
update tablename st
  set country_list = t.iso_list
from translated t
where t.id = st.id;

之后tablename的内容是:

id | country_list
---+-------------
 1 | it,at,de    
 2 | fr,at       
 3 | fr,ch       

很多更好的解决方案是正确规范化模型并在tablenamelookup_table之间创建多对多映射表