【发布时间】:2013-06-09 04:37:30
【问题描述】:
我正在对数据库中网络的各个方面进行建模。我们正在处理的一个更烦人的问题是创建子网范围,然后确定一组给定的 IP 是否在这些范围内。我们当前的模型通过以下列解释了 IPv4 和 IPv6 之间的差异:
[subnet_sk] [int] IDENTITY(1,1) NOT NULL,
[ipv6_network] [char](39) NULL,
[ipv6_broadcast] [char](39) NULL,
[ipv4_network] [char](15) NULL,
[ipv4_broadcast] [char](15) NULL,
[network_type] [char](4) NOT NULL
上面的架构做了一些重要的假设。我们正在使用完全扩展的 IP(192.168.001.001 与 192.168.1.1)进行存储和比较。我们之所以做出这个决定是因为存储 IPv6 addresses numerically in SQL server 的问题(bigint 是无符号的,这意味着我们必须使用六列来表示 IPv6)。
鉴于此表架构,很容易编写一个选择语句来确定任一类型的 IP 是否在表中的范围之间:
select *
from subnet
where '1234:0000:0000:0000:fc12:00ab:0042:1050'
between ipv6_network
and ipv6_broadcast
-- or alternatively for IPv4
select *
from subnet
where '192.168.005.015'
between ipv4_network
and ipv4_broadcast
更难的是给出一个 IP 列表来确定其中哪些位于子网范围之间。 IP 列表将由用户输入提供,并且不存储在数据库中。显然,对于存储在数据库中的数据,我可以进行类似的连接,如下例所示。
例如,用户可以提供1234:0000:0000:0000:fc12:00ab:0042:1050、192.168.001.001 和192.168.1.1。我想出的唯一解决方案是使用 table-valued function to split a list 的 IP 并使用 between 执行连接:
-- this only covers the IPv4 addresses from the above list a similar query would
-- be used for IPv6 and the two queries could be unioned
select sub.*
from fn_SplitList('192.168.001.001,192.168.005.015',',') split
join subnet sub
on split.Data
between sub.ipv4_network
and sub.ipv4_broadcast
虽然使用拆分功能有效,但感觉很笨拙。我花了大部分时间在common table expressions 周围嗅探,但想不出一个可行的实现。理想情况下,单个选择将确定是否从 IPv4 或 IPv6 列中反弹给定的字符串,但如果这不可能,我可以在将 IP 集合交给数据库之前分离列表。
为了更容易回答,我创建了上面的SQL Fiddle。 SQL 中是否有一种机制(我宁愿不使用 T-SQL)给定 IP 列表来确定这些 IP 位于哪些现有子网范围?上述模式是否是解决问题的正确方法,不同的数据模型会导致更简单的解决方案吗?
【问题讨论】:
-
我没有很好的网络知识。我想知道是只有 fn_SplitList() 困扰您,还是您想找到一些更好的方法来处理整个场景?
-
@RaviSingh 给出了这个数据模型,如果我们使用日期列表来确定它们是否在一个范围内,我也会有同样的问题。所以我的问题是我觉得 fn_SplitList 是解决问题的一种方法,但感觉那里有一个更清洁的解决方案。也就是说,如果您告诉我“您的架构是错误的,并且如果您的数据模型以这种方式设置,您的查询会更容易,”我会全神贯注。因此,如果您无法帮助建模但可以帮助更好地查询不使用 fn_SplitList 我对您的解决方案非常感兴趣。
-
最近偶然发现,但为了参考,这里有一些类似的线程讨论 SQL Server 中的字符串拆分:stackoverflow.com/questions/2647/split-string-in-sql 和 stackoverflow.com/questions/314824/…
标签: sql sql-server ipv6 ipv4