MySQL LEAST()具有任意数量的参数;表中最长的匹配

时间:2016-05-24 13:07:16

标签: mysql join network-programming longest-prefix

我想创建一个MySQL查询,以找到子网表中存在的最长匹配(四点式格式的给定IP地址)。

最后,我想创建一个LEFT JOIN,它将在一个表中显示每个四点划线的ip地址,并在另一个表中显示最长的匹配项。我不想创建任何临时表或将其构建为嵌套查询。

我有点像MySQL的新手,但我在想的是这样的:

SELECT `ip_address`
  LEFT JOIN ON 
    SELECT `subnet_id`
    FROM `subnets_table`
    WHERE (`maximum_ip_value` - `minimum_ip_value`) =
    LEAST(<list of subnet intervals>)
      WHERE INET_ATON(<given ip address>) > `minimum_ip_value`
      AND INET_ATON(<given ip address>) < `maximum_ip_value`;

这样minimum_ip_valuemaximum_ip_value是给定子网中可能的最低和最高十进制格式的IP地址 - 例如,对于子网172.16.0.0/16:

minimum_ip_value = 2886729728 (or 172.16.0.0)
maximum_ip_value = 2886795263 (or 172.16.255.255)

并且<list of subnet intervals>包含subnets_table<given ip address>介于minimum_ip_valuemaximum_ip_value之间的所有区间

如果多个间隔包含<given ip address>,则最小间隔(即最小子网,或最特定和“最长”匹配)将被连接。

最终,我真正想要的是与该间隔对应的subnet_id值。

所以我的问题是:

1)我可以使用LEAST()函数和任意数量的参数吗?我想比较subnets_table的每一行,或者更具体地说,比较minimum_ip_valuemaximum_ip_value之间的每一行的间隔,并选择最小的间隔。

2)我可以在LEFT JOIN查询中执行所有这些计算吗?我对任何快速,封装和避免重复查询相同数据的建议都没问题。

我想知道这是否甚至可以在单个查询中执行(即,不查询每个ip地址的子网表),但我不知道如何排除它。请告知它是否会起作用,所以我可以尝试另一种角度。

感谢。

1 个答案:

答案 0 :(得分:0)

经过一些研究和试验&amp;错误,我看到上面的原型查询存在一些问题:

LEAST()函数只接受一定数量的参数。根据我原来的问题,我想要一个可以处理任意数量的参数或表中每一行的函数。这是MySQL中的一个不同功能,MIN()

函数MIN()的优先级低于MySQL中的JOIN函数,并且在任何给定查询中的JOIN函数之后进行求值。因此,我无法JOIN MIN()一组值,因为MIN()JOIN执行时尚不存在。

我能看到解决此问题的唯一方法是执行两个单独的查询:一个使用MIN(),首先执行,另一个使用JOIN,对第一个查询的结果执行。这意味着对于具有 n 行的表,我将执行 n ^ n 查询,而不是 n 查询。这是不可接受的。

要解决此问题,我编写了一个新脚本,在执行任何这些查询之前修改数据库。每个子网都有自己的“桶”ip值,该范围内的所有值都映射到该子网。如果更具体(即,更小)的子网与更不特定(即,更大)的子网重叠,则更具体的范围仅映射到较小的子网,而较大的子网仅保留来自较不特定的范围的值。现在任何给定的IP地址都只属于一个“桶”,并且只映射到一个子网,这是它最具体的匹配。我可以在这场比赛中JOIN,而不必担心MIN()功能。