将逗号分隔的邮政编码字段转换为城市列表

时间:2016-10-09 22:25:38

标签: sql postgresql psql

我有两张桌子:

  1. 人员,列为user_id(唯一)和zipcodes(逗号分隔值;单个值中可能有多个zipcodes);
  2. 位置,包含邮政编码,城市和州的列(每个邮政编码与城市和州相关联,表格包括整个美国)。
  3. 我正在尝试创建一个按user_id密度对城市进行排名的表格。

    因此,首先,我希望在“人员”表中获得一个表格,其中显示user_id以及每个user_id与之关联的城市。 user_id可以与多个城市相关联。

    然后,我计划只计算每个城市的唯一user_ids,并根据user_id对城市进行从最密集到最不密集的排名。

1 个答案:

答案 0 :(得分:1)

将逗号分隔的列值转换为单独的行

将逗号分隔的列转换为单独的行unnest()首先使用string_to_array()从字符串中构建数组:

select 
  user_id, 
  unnest(string_to_array(zipcodes, ',')) AS zipcode
from people

生成测试数据:

create table people(user_id int, zipcodes text);
insert into people values (1, '22333,12354,45398,12398');
into people values (2, '54389,45398,12398');
insert into people values (3, '34534,12398,94385');

结果:

 user_id | zipcode
---------+---------
       1 | 22333
       1 | 12354
       1 | 45398
       1 | 12398
       2 | 54389
       2 | 45398
       2 | 12398
       3 | 34534
       3 | 12398
       3 | 94385

按用户密度排名城市

使用LEFT JOIN将有关城市的信息与关联的zipcodes的提取信息与用户相结合。 COUNT()您的用户并使用窗口函数DENSE_RANK()来指定排名位置。在这种情况下,关系同样如此。

查询:

SELECT
    l.city
  , COUNT(DISTINCT p.user_id) AS distinct_users -- is distinct really needed?
  , DENSE_RANK() OVER (ORDER BY COUNT(DISTINCT p.user_id) DESC) AS city_ranking
FROM location l
LEFT JOIN (
  select 
    user_id, 
    unnest(string_to_array(zipcodes, ',')) AS zipcode
  from people
  ) p USING ( zipcode )
GROUP BY l.city
ORDER BY city_ranking

生成测试数据:

create table location(zipcode text, city text);
insert into location values 
  ('22333', 'City1'), 
  ('12354', 'City2'), 
  ('45398', 'City3'), 
  ('12398', 'City4'), 
  ('54389', 'City5'), 
  ('34534', 'City6'), 
  ('94385', 'City7');

结果:

 city  | distinct_users | city_ranking
-------+----------------+--------------
 City4 |              3 |            1
 City3 |              2 |            2
 City2 |              1 |            3
 City1 |              1 |            3
 City5 |              1 |            3
 City6 |              1 |            3
 City7 |              1 |            3

附加说明

考虑一下你是否真的需要计算不同用户的zipcodes。用户是否可能多次使用相同的邮政编码?

如果是这种情况,您可以在第一个查询中使用DISTINCT,这样您就不需要在排名查询中执行此操作:

select distinct
  user_id,
  unnest(string_to_array(zipcodes, ',')) AS zipcode
from people;

删除排名查询中的不同部分,您就可以了。