如何让多个BETWEEN语句事先不知道它们的数量? (按IP范围检测国家)

时间:2016-03-02 09:47:53

标签: sql sql-server geolocation ip between

我有ip_from,ip_to,country_code列的Ip2LocationLite数据库。

所有IP都是十进制格式(使用函数转换)。

所以我必须检测那些来自某个国家/地区的IP地址的用户。 例如,俄罗斯拥有超过3千个IP范围,我想搜索所有这些范围。

脚本看起来像这样:

SELECT * FROM [dbo].[USERINFO] as UserInfo
WHERE (SELECT gaminator.dbo.IPAddressToInteger (UserInfo.LastIp)) BETWEEN
    (
        SELECT [ip2location].[dbo].[ip2location_db1].ip_from FROM [ip2location].[dbo].[ip2location_db1]
        WHERE [ip2location].[dbo].[ip2location_db1].country_code = 'RU'
    )
    AND
    (
        SELECT [ip2location].[dbo].[ip2location_db1].ip_to FROM [ip2location].[dbo].[ip2location_db1]
        WHERE [ip2location].[dbo].[ip2location_db1].country_code = 'RU'
    )

最后一件事给出错误:

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

这是因为BETWEEN期望一个diapason而不是3,000个diapasons。

如何对此进行编程以使其成为3千个替代品? (根据要检查的diapasons的数量)

3 个答案:

答案 0 :(得分:1)

在没有一些样本记录和预期输出的情况下回答这些问题可能有点棘手。但是,如果我已正确理解您的架构,您可以使用连接而不是子查询。

示例

SELECT 
    * 
FROM 
    [dbo].[USERINFO] as UserInfo
        INNER JOIN [ip2location].[dbo].[ip2location_db1] AS ipRange     ON UserInfo.LastIp BETWEEN ipRange.ip_to AND ipRange.ip_from
WHERE   
    ipRange.country_code = 'RU'
;

答案 1 :(得分:0)

从第一个子查询中获取min/lowest值,从第二个子查询中获取max/highest值以避免错误,并且如果您想将它们用作{{1}的参数条款。

如果您的IP地址是规范的或者可以按数字顺序排序,您可以通过按ASC顺序对它们进行排序并选择第一行(即BETWEEN)并通过排序获得最高IP值来获得最低IP值它们以DESC顺序排列并选择第一行。

答案 2 :(得分:0)

你可以试试这个..

sELECT * FROM [dbo].[USERINFO] as UserInfo
WHERE (SELECT gaminator.dbo.IPAddressToInteger (UserInfo.LastIp)) BETWEEN
    (
        SELECT min([ip2location].[dbo].[ip2location_db1].ip_from )FROM [ip2location].[dbo].[ip2location_db1]
        WHERE [ip2location].[dbo].[ip2location_db1].country_code = 'RU'
    )
    AND
    (
        SELECT max([ip2location].[dbo].[ip2location_db1].ip_to) FROM [ip2location].[dbo].[ip2location_db1]
        WHERE [ip2location].[dbo].[ip2location_db1].country_code = 'RU'
    )