前缀最匹配MySQL

时间:2018-08-03 14:05:03

标签: mysql string-matching prefix

那是我的情况。 我有4个表:记录,提供程序,routing_domain,域。

  • 域:ID,名称(例如“ example.com”)
  • 提供者:id,名称(类似于“ TLC”)
  • 记录:电话号码(varchar),提供商ID(外键 提供者)
  • routing_domain:provider_id(提供商的外键),domain_id (域的外键)和前缀(varchar)。

表格示例

mysql> select id,name from domains;
+----+-----------------------+
| id | name                  |
+----+-----------------------+
|  1 | e164.arpa             |
|  3 | example.com           |
|  0 | localhost.localdomain |
|  4 | luigi.it              |
|  2 | tim.it                |
+----+-----------------------+

mysql> select id,name from providers where id in (9,10);
+----+----------+
| id | name     |
+----+----------+
|  9 | TIM      |
| 10 | VODAFONE |
+----+----------+    

mysql> select * from routing_domain;
+----+--------+-----------+-------------+
| id | prefix | domain_id | provider_id |
+----+--------+-----------+-------------+
|  3 | 3932   |         4 |           9 |
|  1 | 39320  |         2 |           9 |
|  2 | 39321  |         3 |          10 |
+----+--------+-----------+-------------+

现在,

  • 给定了一个具有provider_id 9的电话号码'39320xxxxxxx',我需要获取 domain_id = 2;
  • 给定了一个具有provider_id 9的电话号码'39321xxxxxxx',我需要获取 domain_id = 4;

因此,给定具有provider_id = 9的电话号码'3932xxxxxxxx',我需要进行一些最佳匹配搜索。从6个字符开始搜索前缀,如果不匹配,请尝试5个字符,依此类推,直到3个字符(393)。

我设法通过仅从前缀到5个字符的phone_number搜索来获取正确的域。

类似的东西:

select * FROM records r
left join routing_domain rd on rd.prefix like SUBSTRING(r.phone_number,1,5) and r.provider_id = rd.provider_id 
left join providers p on p.id = rd.provider_id
left join domains d on d.id = rd.domain_id 
where r.name = 'xxxxxxxxxxxx';

有什么建议可以做到最佳匹配? 非常感谢!

  

更新

我尝试过:

select * FROM records r
left join routing_domain rd on on r.phone_number like concat(rd.prefix, '%') and r.provider_id = rd.provider_id 
left join providers p on p.id = rd.provider_id
left join domains d on d.id = rd.domain_id 
where r.name = 'xxxxxxxxxxxx';

现在,如果我搜索“ 39325xxxxxxx”,则存在前缀为“ 3932”的匹配项, 但是如果我搜索“ 39320xxxxxxx”,则两个前缀都将匹配,并且搜索返回2行。

2 个答案:

答案 0 :(得分:1)

一种选择是拥有一个子查询,该子查询为您提供最长匹配provider_idprefix的前缀。像这样:

select domain_id from routing_domain
where
  provider_id = 9
  and '39321xxxxxxx' like concat(prefix, '%')
  and length(prefix) =
  (    select max(length(prefix))
       from routing_domain
       where 
         provider_id = 9
         and '39321xxxxxxx' like concat(prefix, '%')
  )

见我的小提琴here

答案 1 :(得分:1)

http://sqlfiddle.com/#!9/2e36df/10

SELECT r.*, 
       MAX(IF(rd.prefix = LEFT(r.phone_number,5),rd.prefix,
             IF(rd.prefix = LEFT(r.phone_number,4),rd.prefix,
                IF(rd.prefix = LEFT(r.phone_number,3),rd.prefix,''))))
FROM records r
LEFT JOIN routing_domain rd
ON r.provider_id = rd.provider_id
GROUP BY r.id

并使其更接近您的尝试:

http://sqlfiddle.com/#!9/2e36df/17

SELECT t.*, p.*, d.*
FROM (
  SELECT r.*, 
         MAX(IF(rd.prefix = LEFT(r.phone_number,5),rd.id,
               IF(rd.prefix = LEFT(r.phone_number,4),rd.id,
                  IF(rd.prefix = LEFT(r.phone_number,3),rd.id,'')))) as rd_id
  FROM records r
  LEFT JOIN routing_domain rd
  ON r.provider_id = rd.provider_id
  #WHERE r.phone_number = '393xxxxxxxxxx'
  GROUP BY r.id
  ) t
LEFT JOIN routing_domain rd
ON t.rd_id = rd.id
LEFT JOIN providers p 
ON p.id = rd.provider_id
LEFT JOIN domains d 
ON d.id = rd.domain_id