【问题标题】:How to match phone number prefix to country from phonenumber in SQL如何从 SQL 中的电话号码将电话号码前缀与国家/地区匹配
【发布时间】:2020-03-21 09:06:00
【问题描述】:

我正在尝试从数字列表中提取国家代码前缀,并将它们与它们所属的区域相匹配。数据可能如下所示:

| id | phone_number   |
|----|----------------|
| 1  | +27000000000   |
| 2  | +16840000000   |
| 3  | +10000000000   |
| 4  | +27000000000   |

这里的国家代码是:

  • 美属萨摩亚:+1684
  • 美国和加勒比地区:+1
  • 南非:+27

期望的结果是这样的:

| country                     | count |
|-----------------------------|-------|
| South Africa                | 2     |
| American Samoa              | 1     |
| United States and Caribbean | 1     |

有一些困难是因为

  • 国家/地区前缀代码从 1 到 4 个数字不等,即使没有国家/地区前缀,
  • 电话号码长度因地而异。
  • 我没有对此数据库的写入权限,因此添加另一列虽然可能是最好的解决方案,但在此用例中不起作用

这是我目前的解决方案:

SELECT 
CASE
    WHEN SUBSTRING(phone_number,1,5) = '+1684' THEN 'American Samoa'
    WHEN SUBSTRING(phone_number,1,5) = '+1264' THEN 'Anguilla'
    ...
    WHEN SUBSTRING(phone_number,1,5) = '+1599' THEN 'Saint Martin'
    WHEN SUBSTRING(phone_number,1,4) = '+355' THEN 'Albania'
    WHEN SUBSTRING(phone_number,1,4) = '+213' THEN 'Algeria'
    ...
    WHEN SUBSTRING(phone_number,1,4) = '+263' THEN 'Zimbabwe'
    WHEN SUBSTRING(phone_number,1,3) = '+93' THEN 'Afghanistan'
    WHEN SUBSTRING(phone_number,1,3) = '+54' THEN 'Argentina'
    ...
    WHEN SUBSTRING(phone_number,1,3) = '+58' THEN 'Venezuela'
    WHEN SUBSTRING(phone_number,1,3) = '+84' THEN 'Vietnam'
    WHEN SUBSTRING(phone_number,1,2) = '+1' THEN 'United States and Caribbean'
    WHEN SUBSTRING(phone_number,1,2) = '+7' THEN 'Kazakhstan, Russia'
    ELSE 'unknown'
END as country_name,
count(*)
FROM users
GROUP BY country_name
order by count desc

有 ~205 个WHEN ... THEN 案例。它似乎非常低效并且超时。我认为这是因为它在每一行上运行模式匹配。这需要扩展到大约数千万行

有没有更有效的方法来做到这一点?

我使用的是 postgreSQL 9.6.16

【问题讨论】:

  • 为什么不单独为代码前缀列
  • 这不是一个非常适合在数据库中完成的任务;相反,您应该从原始数据源中引入国家代码。旁注:美国号码看起来像+1000000000;一个有效的美国号码由 10 位数字组成,例如+12128675309.
  • @JAR 目前我没有办法进行数据库迁移,我只有读取权限。将更新问题。
  • 好点@TimBiegeleisen - 我想我只是想突出前缀,而不是添加潜在的实数????
  • 您最好使用计算机语言完成工作,然后从用户中选择 * 来访问数据库。

标签: sql postgresql phone-number libphonenumber


【解决方案1】:

尽管阅读了整个表格,但在这里索引可能会有所帮助。为了聚合每个国家代码的数据,DBMS 必须按国家代码对所有行进行排序。排序是一项昂贵的操作,尤其是在大型数据集上。如果你有一个国家代码的索引,DBMS 会在索引中找到已经预先排序的代码,并且可以避免对数据进行排序的工作。

一列中没有单独的国家代码,但每个电话号码都以代码开头,因此您可以索引完整的电话号码:

create index idx on users (phone_number);

那么你必须让 DBMS 清楚你对字符串的开头感兴趣,所以它会考虑使用索引。在电话号码上调用 SUBSTRING 之类的函数可能会使 DBMS 对此视而不见。请改用LIKE。根据文档 (https://www.postgresql.org/docs/9.3/indexes-types.html),字符串索引可以与 LIKE 'something%' 一起使用:

WHEN phone_number LIKE '+1684%' THEN 'American Samoa'

不能保证这会有所帮助,但我认为值得一试。这取决于优化器是否看到了使用索引中预先排序的电话号码的优势。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-05
    • 1970-01-01
    • 2015-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多