MySQL 匹配连接表中的最长前缀
MySQL matching longest prefix in joined tables
我们有 2 个表,“callsdb”保存 phone 通话记录,“regionsdb”保存区域相关前缀。
我们需要做的是生成一个连接列表匹配“callsdb.destination_number”,LONGEST前缀为“regionsdb.country_prefix".
备注:
1) "callsdb" 中的 Phone 号码可能有也可能没有 前缀。
2) Phone "callsdb" 中的号码在国家/地区前缀之前有一个额外的“00”前缀。
我们尝试了以下查询,但它的性能极差。
有没有更快的方法来实现这个目标?
SELECT
uid, call_date, destination, name, country_prefix, duration, unit_cost
FROM
callsdb.calls
INNER JOIN
regionsdb.regions
ON
(
(
(calls.destination_number LIKE CONCAT('100100', regions.country_prefix, '%'))
AND
(
LENGTH(regions.country_prefix) =
(
SELECT MAX(LENGTH(regions.country_prefix))
FROM regionsdb.regions
WHERE calls.destination_number LIKE CONCAT('100100', regions.country_prefix, '%')
)
)
)
OR
(
(calls.destination_number LIKE CONCAT('00', regions.country_prefix, '%'))
AND
(
LENGTH(regions.country_prefix) =
(
SELECT MAX(LENGTH(regions.country_prefix))
FROM regionsdb.regions
WHERE calls.destination_number LIKE CONCAT('00',regions.country_prefix, '%')
)
)
)
)
ORDER BY call_date DESC;
编辑:
通过更改查询的 "ON" 部分减少了执行时间。但还是太慢了!
ON
(
(
(IF(calls.destination_number LIKE '1001%', SUBSTRING(calls.destination_number, 5), calls.destination_number) LIKE CONCAT('00', regions.country_prefix, '%'))
AND
(
LENGTH(regions.country_prefix) =
(
SELECT MAX(LENGTH(regions.country_prefix))
FROM regionsdb.regions
WHERE IF(calls.destination_number LIKE '1001%', SUBSTRING(calls.destination_number, 5), calls.destination_number) LIKE CONCAT('00', regions.country_prefix, '%')
)
)
)
)
编辑 2:
在 select "dst" 更正为 "destination".
您可以将 group by
与 group_concat
结合使用,这样可以按照 country_prefix
长度的降序连接来自 regions
table 的字段.然后你可以提取第一个。
我将假定字段 name
、unit_cost
来自 regions
table,如果其他字段也是,则对它们应用相同的逻辑。 group by
子句应列出 calls
table 中的所有选定字段,或至少列出关键字段:
select c.uid, c.call_date, c.dst,
substring_index(
group_concat(r.name order by length(r.country_prefix) desc),
',', 1) as name,
substring_index(
group_concat(r.country_prefix order by length(r.country_prefix) desc),
',', 1) as country_prefix,
c.duration,
substring_index(
group_concat(format(r.unit_cost, 2)
order by length(r.country_prefix) desc),
',', 1) as unit_cost
from callsdb.calls c
inner join regionsdb.regions r
on (left(c.destination_number, 6 + length(r.country_prefix))
= concat('100100', r.country_prefix)
or mid(c.destination_number, 3, length(r.country_prefix))
= r.country_prefix
)
group by c.uid,
c.call_date,
c.dst,
c.duration
我们有 2 个表,“callsdb”保存 phone 通话记录,“regionsdb”保存区域相关前缀。 我们需要做的是生成一个连接列表匹配“callsdb.destination_number”,LONGEST前缀为“regionsdb.country_prefix".
备注:
1) "callsdb" 中的 Phone 号码可能有也可能没有 前缀。
2) Phone "callsdb" 中的号码在国家/地区前缀之前有一个额外的“00”前缀。
我们尝试了以下查询,但它的性能极差。 有没有更快的方法来实现这个目标?
SELECT
uid, call_date, destination, name, country_prefix, duration, unit_cost
FROM
callsdb.calls
INNER JOIN
regionsdb.regions
ON
(
(
(calls.destination_number LIKE CONCAT('100100', regions.country_prefix, '%'))
AND
(
LENGTH(regions.country_prefix) =
(
SELECT MAX(LENGTH(regions.country_prefix))
FROM regionsdb.regions
WHERE calls.destination_number LIKE CONCAT('100100', regions.country_prefix, '%')
)
)
)
OR
(
(calls.destination_number LIKE CONCAT('00', regions.country_prefix, '%'))
AND
(
LENGTH(regions.country_prefix) =
(
SELECT MAX(LENGTH(regions.country_prefix))
FROM regionsdb.regions
WHERE calls.destination_number LIKE CONCAT('00',regions.country_prefix, '%')
)
)
)
)
ORDER BY call_date DESC;
编辑:
通过更改查询的 "ON" 部分减少了执行时间。但还是太慢了!
ON
(
(
(IF(calls.destination_number LIKE '1001%', SUBSTRING(calls.destination_number, 5), calls.destination_number) LIKE CONCAT('00', regions.country_prefix, '%'))
AND
(
LENGTH(regions.country_prefix) =
(
SELECT MAX(LENGTH(regions.country_prefix))
FROM regionsdb.regions
WHERE IF(calls.destination_number LIKE '1001%', SUBSTRING(calls.destination_number, 5), calls.destination_number) LIKE CONCAT('00', regions.country_prefix, '%')
)
)
)
)
编辑 2: 在 select "dst" 更正为 "destination".
您可以将 group by
与 group_concat
结合使用,这样可以按照 country_prefix
长度的降序连接来自 regions
table 的字段.然后你可以提取第一个。
我将假定字段 name
、unit_cost
来自 regions
table,如果其他字段也是,则对它们应用相同的逻辑。 group by
子句应列出 calls
table 中的所有选定字段,或至少列出关键字段:
select c.uid, c.call_date, c.dst,
substring_index(
group_concat(r.name order by length(r.country_prefix) desc),
',', 1) as name,
substring_index(
group_concat(r.country_prefix order by length(r.country_prefix) desc),
',', 1) as country_prefix,
c.duration,
substring_index(
group_concat(format(r.unit_cost, 2)
order by length(r.country_prefix) desc),
',', 1) as unit_cost
from callsdb.calls c
inner join regionsdb.regions r
on (left(c.destination_number, 6 + length(r.country_prefix))
= concat('100100', r.country_prefix)
or mid(c.destination_number, 3, length(r.country_prefix))
= r.country_prefix
)
group by c.uid,
c.call_date,
c.dst,
c.duration