4

我有一张包含大约 130 000 条电话号码记录的表格。这些数字的格式都像这样 +4311234567。这些号码总是包括国际国家代码、本地区号,然后是电话号码,有时还包括分机号。

有一个网络服务可以检查表中的呼叫者号码。该服务已经有效。但是现在客户还希望,如果有人从公司呼叫,其号码已经在数据库中但不是他的分机,那么服务将返回一些结果。

表格示例。

   **身份证** | **电话号码** | **姓名**   
| 1 | +431234567 | A公司  
| 2 | +431234567890 | A公司员工  
| 3 | +4398765432 | b公司

现在,如果 A 公司的某人使用不同的分机号(例如 +43123456777)拨打电话,则它应该返回 id1。但问题是,我不知道扩展名有多少位数。它可能有 3,4 位或更多位。

字符串类型的匹配是否有任何模式?

数据存储在 sql2005 数据库中。

谢谢

编辑:
我从 crm 系统获得的电话号码。我已经与 crm 的管理员谈过,他正试图以不同的格式向我发送数据。

   **身份证** | **电话号码** |**分机号** | **姓名**   
| 1 | +431234567 | | A公司  
| 2 | +431234567 | 890 | A公司员工  
| 3 | +4398765432 | | b公司
4

7 回答 7

4

有没有办法确定存储号码的确切部分是扩展名?或者是没有扩展的“基本”数字被存储。如果是,您可以检查数据库中的数字(不带扩展名)是否是要检查的当前号码的前缀。前缀表示从开头开始的字符串的子字符串。

但是,如果您的数据库中只有带有扩展名的数字,并且无法找出属于它的数字,我相信您无法找到确切的解决方案。

于 2010-05-04T13:26:28.787 回答
2

无需在数据库中查找电话号码,您可以反转问题并检查数据库中的每个号码,以查看它是否匹配或作为传入号码的前缀。

假设您从来电显示中获得了一个电话号码,例如 +431234567891,那么

SELECT name, id
FROM Table
WHERE CHARINDEX(telephonenumber, "+431234567891") > 0;

将返回公司,如果是 +431234567890 将返回 2 条记录

  • 公司
  • 实际扩展

如果您可以处理从客户端返回的两行,则上述内容应该没问题。

预处理数据更好(性能方面),但为此您需要更详细地描述数据,例如:

  • 扩展名只有 3 位和 4 位数字,
  • 是基数,始终为 9 或 10 位数字,
  • 对于有分机等的公司,您是否总是至少有一个分机号码...
于 2010-05-04T13:59:26.217 回答
2

鉴于每个公司的分机位数可能不同,并且每个国家地区代码的号码中的位数可能不同,因此要有效地解决这个问题是一个棘手的问题。

即使您将数据表拆分为基数和扩展名,您仍然必须将传入的数字拆分为基数和扩展名,我实际上认为这会使事情复杂化。

我倾向于尝试的是:

原始格式

  1. 尝试将传入号码与数据库匹配。
    • 如果它与一条记录匹配,您就会得到答案 - 一个特定的人。
    • 如果它匹配多个记录,则出现问题,因此失败。
    • 否则,您必须找到公司:
  2. 从传入号码中去掉尾随数字,并再次尝试将其与数据库匹配。
    • 如果位数低于阈值(可能是 6 位数),那么您的搜索可能会失败。这只是为了限制在找不到数字时执行的数据库搜索的数量。
    • 如果它没有匹配任何记录,那么您需要再次尝试此步骤。
    • 如果它匹配多个记录,则出现问题,因此失败。
    • 如果它与一条记录完全匹配,那么您将获得下一个最佳答案 - 公司。

例如,搜索“+43123456777”:

  • +43123456777 匹配 0 个条目。
  • +4312345677 匹配 0 个条目。
  • +431234567 匹配 1 个条目:“A 公司”

这种方法的主要失败模式是公司是否有可变长度的扩展号码。例如,考虑如果 431234567890 和 43123456789 都是有效数字但只有第二个在数据库中会发生什么。如果来电号码是 431234567890,那么 43123456789 会匹配错误。

拆分格式

这有点复杂,但更健壮。

  1. 尝试将传入号码与数据库匹配。
    • 如果它与一条记录匹配,那么您就有了答案——公司。
    • 如果匹配多条记录,匹配​​不带扩展名的条目,您就找到了该公司。
    • 否则,您必须找到基本公司编号和分机:
  2. 从传入号码中去掉尾随数字,并再次尝试将其与数据库匹配。
    • 如果位数低于阈值(可能是 6 位数),那么您的搜索可能会失败。这只是为了限制在找不到数字时执行的数据库搜索的数量。
    • 如果它没有匹配任何记录,那么您需要再次尝试此步骤。
    • 如果它与一条记录匹配,那么您已经找到了答案 - 公司。
    • 如果它匹配多条记录,那么您已经找到了公司的基本号码,因此现在知道了分机号,因此可以尝试查找特定的人:
  3. 从原始传入号码的开头剥离基数,并使用它来搜索具有该基数的记录的扩展名。
    • 如果它与一条记录完全匹配,则您已找到特定的人。
    • 如果它不匹配特定的人,匹配不带扩展名的条目,您就找到了公司。

例如,搜索“+43123456777”:

  • +43123456777 匹配 0 个条目。
  • +4312345677 匹配 0 个条目。
  • +431234567 匹配 2 个条目:“empty:Company A”和“890:employee in company A”
  • 在这两个匹配项中,“77”不匹配任何内容,因此返回空扩展名:“Company A”。

实施说明

如上所述,该算法确实存在一些效率问题。如果数据库查找开销很大,它与电话号码的长度有一个线性成本,特别是在数据库中不存在类似号码的情况下(例如,如果传入的号码来自哈萨克斯坦,但没有哈萨克斯坦数据库中的数字 *8')。

不过,您可以相对容易地添加一些优化。如果与您打交道的大多数公司都使用 3 或 4 位扩展名,那么您可以先从末尾剥离 4 位数字,然后进行二进制切分,直到找到答案。在许多情况下,这会将 15 位数字减少到 4 或 5 个,最多 6 次查找。

此外,每次缩小选择范围时,您只能在前一个选择范围内进行选择,而不必在整个数据库中进行选择。

附加实施说明

终于弄清楚了Unreason 的答案是如何工作的,我可以看到这是一个更简单、更优雅的解决方案。我希望我只是简单地在传入号码中查找数据库号码,而不是相反。

我唯一担心的是,telephonenumber对数据库中的每一个都执行此操作可能会对服务器产生过多的要求。我建议在最大压力下对该解决方案进行基准测试,看看它是否会导致问题。如果没有,很好 - 使用它。如果是这样,请考虑实现我的算法的简单形式并再次进行压力测试。如果性能仍然太低,请尝试我的二分搜索建议。

于 2010-05-04T15:36:22.163 回答
1

分机中的位数是特定于 PBX 的。区号+电话号码中的位数因国家/地区/运营商而异。

一种方法是定义其他规则,例如...

+43123 | 12

... 说以 +43123 开头的任何内容都是 12 位数字,而除此之外的任何内容都是扩展名:这使您可以使用(可配置而不是硬编码)数据来指定扩展名的开始位置。

另一种方法可能是坚持对于任何带扩展名的号码条目也应该有一个相应的不带扩展名的号码,如您的“公司 A”示例所示。

于 2010-05-04T13:25:24.457 回答
1

好吧,我对电话号码系统的理解是,不能存在两个有效/完整的号码,其中一个是另一个的前缀。这里的一个常见恶作剧是把你的电话号码设为 11 05 32 之类的,其中 110 是德国紧急警察号码。

所以 - 如果您可以更改数据库结构并预处理数据,您可以查找具有相同前缀的数字(首先订购它们,如果较长的开头以最短的它们是扩展名)。每场比赛都是

  • 一个基数(最短的一个)
  • 直接号码加分机(所有更长的)

如果可能的话,我会在数据库中标记它们以便更快地查找。

这种方法不适合您拥有通用默认扩展名的情况。在这里,很多公司都会给出 1234567-0 之类的外部号码,其中 0 可以替换为 2-4 位数的扩展名。对于这些情况,我的方法会失败 - 对于您的示例数据,它会起作用吗?

于 2010-05-04T13:28:53.527 回答
1

如果您要处理来自不同国家的电话号码,那几乎是不可能的。长度经常变化,即使在同一个国家。如果你知道长度是多少(或者你想维护一个像 ChrisW 这样的列表),你可以在搜索公司的电话号码之前使用 LEFT(field, x) 函数截断电话号码。请注意,如果您正在执行连接,它可能会运行得更慢,因为它必须在每一行上运行该函数。

于 2010-05-04T13:30:19.923 回答
-1

如果没有更多信息,这将是不可能的:如果您的表结构如上,系统无法知道哪一部分是基数,哪一部分是扩展。因此它将为任何以“+439”开头的(未知)号码返回“公司 b”。

编辑(@MarkBooth)

我坚持我的说法,即如果没有额外的信息,这是不可能的。只是为了更清楚:假设我们的数据库中有以下信息

...
+43316852132 - ....
+433168731 - Company A (reception)
+433168739999 - Company A, Mr. X
+433168911321 - ....
...

这些号码的结构是 +43 (316) 873 - 1,程序不知道。因此,如果一个号码 +43316872133(带结构的 +43 (316) 87 21 33)正在调用(不在数据库中),您(以及您的软件:))无法判断它是否属于 A 公司信息。

唯一的解决方案是为可以进行简单前缀搜索的公司维护“基数”。

于 2010-05-04T13:29:38.300 回答