【问题标题】:MS Access SQL query for IP address rangeMS Access SQL 查询 IP 地址范围
【发布时间】:2014-05-16 06:26:17
【问题描述】:

IP 地址在 Access 数据库中以文本值的形式存储在联结表中,格式为 192.168.0.1 - 192.168.0.254。

连接表,例如区域

Name       IPAddress
Area1      192.168.0.1 - 192.168.0.254
Area2      192.168.1.1 - 192.168.1.254

我需要能够搜索这些范围之间的记录,例如

SELECT * FROM devices WHERE ipaddress = 192.168.0.1 /Returns record Name1

SELECT * FROM tablename WHERE ipaddress BETWEEN 192.168.0.1 AND 192.168.0.25 /Returns record Name1,Name2,Name3,etc

【问题讨论】:

  • 列的数据类型是什么?
  • 添加整数列stackoverflow.com/questions/2138706/… 感觉如何?
  • 您需要将 IP 地址转换为一个数字(实际上是数字),然后进行比较。即 192.168.0.1 = 192*(2^24) + 168 * (2^16) + 0*(2^8) + 1 * (2^0)。找到一个将 IP 地址转换为数字的函数并使用它来比较......就像这样:aboutmyip.com/AboutMyXApp/IP2Integer.jsp
  • @Elias - 他们是TEXT
  • @Remou - 我很想但是不能,因为数据库是由第三方提供的,并且更改数据库将使任何支持无效。

标签: sql ms-access


【解决方案1】:

一个成功的方法由三个部分组成:

  1. 解析IPAddress 列并将其拆分为两个逻辑(文本)列:IPAddressLowIPAddressHigh,它们捕获一个区域的 IP 范围。让我们称之为qryAreas

    select
      [Name]
    , ... as IPAddressLow
    , ... as IPAddressHigh
    from Areas
    
  2. 实现一个函数(在 VBA 中,然后您可以从 Access SQL 中调用该函数)来比较 IP 地址。比较器函数可能类似于:

    ' Returns:
    '  -1 if IP1 < IP2
    '   0 if IP1 = IP2
    '   1 if IP1 > IP2
    Function CompareIPAddresses(ip1 As String, ip2 As String) As Integer
      ip1_arr = Split(ip1, ".")
      ip2_arr = Split(ip2, ".")
    
      For i = 0 To 3
        ip1_arr(i) = CLng(ip1_arr(i))
        ip2_arr(i) = CLng(ip2_arr(i))
      Next i
    
      If ip1 = ip2 Then
        retval = 0
      ElseIf ip1_arr(0) < ip2_arr(0) Then
        retval = -1
      ElseIf ip1_arr(0) = ip2_arr(0) And ip1_arr(1) < ip2_arr(1) Then
        retval = -1
      ElseIf ip1_arr(0) = ip2_arr(0) And ip1_arr(1) = ip2_arr(1) And ip1_arr(2) < ip2_arr(2) Then
        retval = -1
      ElseIf ip1_arr(0) = ip2_arr(0) And ip1_arr(1) = ip2_arr(1) And ip1_arr(2) = ip2_arr(2) And ip1_arr(3) < ip2_arr(3) Then
        retval = -1
      Else
        retval = 1
      End If
    
      CompareIPAddresses = retval
    End Function
    
  3. 在查询中使用上述函数来确定 IP 地址是否等于某个值或落在某个范围内。例如,如果您有一个地址 192.168.1.100 并想知道它在哪个区域,您可以这样做:

    select [Name]
    from qryAreas
    where CompareIPAddresses(IPAddressLow, '192.168.1.100') in (-1, 0)
    and CompareIPAddresses('192.168.1.100', IPAddressHigh) in (-1, 0)
    

这里的 where 子句与更优雅的 where 192.168.1.100 between IPAddressLow and IPAddressHigh 语法相当笨拙,因为您没有本机 IP 地址数据类型及其相应的运算符 - 所以您自己滚动。

【讨论】:

    【解决方案2】:

    要搜索一系列 IP 地址,您可以使用类似这样的 VBA 小功能

    Option Compare Database
    Option Explicit
    
    Public Function ZeroPaddedIP(IP As String) As String
        Dim rtn As String, octets() As String, octet As Variant
        rtn = ""
        octets = Split(IP, ".")
        For Each octet In octets
            rtn = rtn & "." & Format(Val(octet), "000")
        Next
        ZeroPaddedIP = Mid(rtn, 2)  ' trim leading "."
    End Function
    

    它用前导零填充八位字节

    ZeroPaddedIP("192.168.0.1") --> "192.168.000.001"
    

    你的查询可以做类似的事情

    SELECT * FROM tablename 
    WHERE ZeroPaddedIP(ipaddress) BETWEEN "192.168.000.001" AND "192.168.000.025"
    

    该查询将执行表扫描,因为它不能使用 [ipaddress] 上的任何现有索引。如果性能是一个问题,您可能会考虑以填充形式存储您的 IP 地址(代替或补充正常的未填充格式)。

    编辑

    对于名为 [NetworkData] 的测试表 ...

    ID  IP             Description
    --  -------------  -----------
     1  192.168.0.1    router     
     2  192.168.0.2    test server
     3  192.168.0.3    dev server 
     4  192.168.0.102  test client
     5  192.168.0.103  dev client 
    

    ...上面显示的 VBA 函数可以在这样的 Access 查询中使用...

    SELECT
        IP,
        ZeroPaddedIP(IP) AS PaddedIP
    FROM NetworkData
    

    ...产生以下结果...

    IP             PaddedIP
    -------------  ---------------
    192.168.0.1    192.168.000.001
    192.168.0.2    192.168.000.002
    192.168.0.3    192.168.000.003
    192.168.0.102  192.168.000.102
    192.168.0.103  192.168.000.103
    

    ... 但仅当查询是从 Access 本身内部执行时。可以从以下查询中获得相同的结果,但如果查询是从其他应用程序(如 Excel)针对 Access 数据库运行的,则此查询将起作用:

    SELECT
        IP,
        Right('000' & Octet1, 3) & '.' & Right('000' & Octet2, 3) & '.' & Right('000' & Octet3, 3) & '.' & Right('000' & Octet4, 3) AS PaddedIP
    FROM
        (
            SELECT
                IP,
                Octet1,
                Octet2,
                Left(TheRest2, InStr(TheRest2, '.') - 1) AS Octet3, 
                Mid(TheRest2, InStr(TheRest2, '.') + 1) AS Octet4
            FROM
                (
                    SELECT
                        IP,
                        Octet1,
                        Left(TheRest1, InStr(TheRest1, '.') - 1) AS Octet2, 
                        Mid(TheRest1, InStr(TheRest1, '.') + 1) AS theRest2
                    FROM
                        (
                            SELECT 
                                IP, 
                                Left(IP, InStr(IP, '.') - 1) AS Octet1, 
                                Mid(IP, InStr(IP, '.') + 1) AS theRest1 
                            FROM NetworkData
                        ) AS q1
                ) AS q2
        ) AS q3
    

    所以,如果您从 Excel(或其他任何地方)查询数据并尝试使用

    SELECT * FROM NetworkData 
    WHERE IP Between '192.168.0.1' And '192.168.0.25'
    

    你会得到以下不正确的结果

    ID  IP             Description
    --  -------------  -----------
     1  192.168.0.1    router     
     2  192.168.0.2    test server
     4  192.168.0.102  test client
     5  192.168.0.103  dev client 
    

    如果你使用过

    SELECT NetworkData.* 
    FROM
        NetworkData
        INNER JOIN
        (
            SELECT
                IP,
                Right('000' & Octet1, 3) & '.' & Right('000' & Octet2, 3) & '.' & Right('000' & Octet3, 3) & '.' & Right('000' & Octet4, 3) AS PaddedIP
            FROM
                (
                    SELECT
                        IP,
                        Octet1,
                        Octet2,
                        Left(TheRest2, InStr(TheRest2, '.') - 1) AS Octet3, 
                        Mid(TheRest2, InStr(TheRest2, '.') + 1) AS Octet4
                    FROM
                        (
                            SELECT
                                IP,
                                Octet1,
                                Left(TheRest1, InStr(TheRest1, '.') - 1) AS Octet2, 
                                Mid(TheRest1, InStr(TheRest1, '.') + 1) AS theRest2
                            FROM
                                (
                                    SELECT 
                                        IP, 
                                        Left(IP, InStr(IP, '.') - 1) AS Octet1, 
                                        Mid(IP, InStr(IP, '.') + 1) AS theRest1 
                                    FROM NetworkData
                                ) AS q1
                        ) AS q2
                ) AS q3
        ) AS q4
            ON q4.IP = NetworkData.IP
    WHERE q4.PaddedIP Between '192.168.000.001' And '192.168.000.025'
    

    您将收到以下正确结果

    ID  IP           Description
    --  -----------  -----------
     1  192.168.0.1  router     
     2  192.168.0.2  test server
     3  192.168.0.3  dev server 
    

    【讨论】:

    • 嗯,我可以在 Excel 中使用该函数,因为我可以使用 Excel 查询数据库吗?
    猜你喜欢
    • 1970-01-01
    • 2019-08-30
    • 2013-08-22
    • 2013-11-23
    • 1970-01-01
    • 2022-07-22
    • 2020-10-07
    • 2017-11-27
    • 2010-09-10
    相关资源
    最近更新 更多