使用SQL查找最具体的前缀

时间:2009-10-09 06:49:39

标签: sql oracle

我有一点SQL问题。这是我的表格:

areas(id, name, sla_id)
areas_groups(id, group_id, areaprefix)

sla_id是来自不同来源的标识符 - 它是唯一的,但区域有自己的自动递增主键。

areaprefix字段很有意思。它只包含sla_id的前几位数字,并且是唯一的。每个区域只能存在于一个组中,因此该区域属于具有最具体前缀的组。例如:

Group 12's area prefixes: 105, 110, 115, 805
Group 13's area prefixes: 1, 8

Area sla_id = 10533071 matches both group 12 (105*) and group 13 (1*)
              "105" is longer, so this area is in group 12
Area sla_id = 81031983 matches only group 13 (8*)

这样做的原因是我们可以轻松地为不属于任何其他群体的区域制作一个“全能”组。

我可以像这样找到一个区域:

-- eg: area with sla_id 105055200
SELECT * FROM (
    SELECT group_id
    FROM areas_groups
    WHERE SUBSTR('105055200', 0, LENGTH(area_prefix)) = area_prefix
    ORDER BY LENGTH(area_prefix) DESC
)
WHERE rownum = 1;

(我提到过这是Oracle吗?)

另一种方式是棘手的:给定一个组ID,我想找到属于该组的所有区域。也就是说,给定第13组,我希望所有区域以1或8开头但不是105,110,115或805(在本例中)。

我最接近的是:

SELECT a.id, a.sla_id, MAX(LENGTH(ag.area_prefix)), ag.group_id
FROM areas a INNER JOIN areas_groups ag
    ON (SUBSTR(a.sla_id, 0, LENGTH(ag.area_prefix)) = ag.area_prefix)
WHERE a.sla_id IS NOT NULL
GROUP BY a.id, a.sla_id, ag.group_id

返回如下数据:

 id     sla_id    leng   group_id
583    105308400    3    12
583    105308400    1    13
584    105556700    3    12
584    105556700    1    13

所以,如果我只能抓住每个id长度最长的group_id ......我感觉我很亲密,但只是错过了一个小小的东西......任何人都可以帮助我摆脱我的不幸?

2 个答案:

答案 0 :(得分:2)

select id
,      sla_id
,      leng
,      group_id
,      (row_number() over (partition by id order by leng desc)) rn 
from 
(
SELECT a.id, a.sla_id, MAX(LENGTH(ag.area_prefix)) leng, ag.group_id
FROM areas a INNER JOIN areas_groups ag
    ON (SUBSTR(a.sla_id, 0, LENGTH(ag.area_prefix)) = ag.area_prefix)
WHERE a.sla_id IS NOT NULL
GROUP BY a.id, a.sla_id, ag.group_id
)
where rn = 1

答案 1 :(得分:1)

这在Oracle上未经过测试,但我相信Oracle自版本9以来一直支持COALESCE作为字符串函数,所以除非您正在使用旧版本的Oracle,否则这应该没问题。

我假设还有一组包含两个字符的area_prefix个记录。

select  a.id
        ,a.sla_id
        ,coalesce(ag3.area_prefix,ag2.area_prefix,ag1.area_prefix) area_prefix
        ,coalesce(ag3.group_id,ag2.group_id,ag1.group_id) group_id
from areas a
left join areas_groups ag3
on        substr(a.sla_id,1,3) = ag3.area_prefix
left join areas_groups ag2
on        substr(a.sla_id,1,2) = ag2.area_prefix
left join areas_groups ag1
on        substr(a.sla_id,1,1) = ag1.area_prefix