9

データベース内のネットワークのさまざまな側面のモデリングに取り組んでいます。私たちが対処している厄介な問題の 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.001vs. ) を使用しています。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:1050192.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を使用しないことをお勧めします)? 上記のスキーマは問題への正しいアプローチでさえありますか?異なるデータモデルがより簡単な解決策につながりますか?

4

4 に答える 4