データベース内のネットワークのさまざまな側面のモデリングに取り組んでいます。私たちが対処している厄介な問題の 1 つは、サブネット範囲を作成し、特定の 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
vs. ) を使用しています。192.168.1.1
この決定を行ったのは、IPv6 アドレスを SQL サーバーに数値で格納する際の問題(bigint は符号なしであるため、IPv6 を表すために 6 つの列を使用する必要があるためです)。
このテーブル スキーマを考えると、いずれかのタイプの IP がテーブル内の範囲内にあるかどうかを判断するために、select ステートメントを 1 回記述するのは非常に簡単です。
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
。私が思いついた唯一の解決策は、テーブル値関数を使用して IP のリストを分割し、次の間を使用して結合を実行することです。
-- 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
分割機能を利用している間はハッキーな感じがします。私は朝の大部分を一般的なテーブル式の周りを嗅いで過ごしましたが、うまくいく実装を思いつきませんでした. 理想的には、特定の文字列を IPv4 列または IPv6 列からバウンスするかどうかを単一の選択で決定しますが、それが不可能な場合は、IP のコレクションをデータベースに渡す前にリストを分離できます。
回答を簡単にするために、上記のSQL Fiddleを作成しました。IPのリストが与えられたときに、それらのIPがどの既存のサブネット範囲にあるかを判断するメカニズムがSQLにありますか(私はT-SQLを使用しないことをお勧めします)? 上記のスキーマは問題への正しいアプローチでさえありますか?異なるデータモデルがより簡単な解決策につながりますか?