少数の行で問題ない次の関数を作成しました。大きなテーブルの場合、IP はバイナリ形式で保存する必要があります。
CREATE FUNCTION IPAddressInRange
(
@IPAddress NVARCHAR(MAX),
@IPRange NVARCHAR(MAX)
)
RETURNS BIT AS
BEGIN
DECLARE @SlashPos INT = CHARINDEX('/', @IPRange);
DECLARE @Network NVARCHAR(MAX) = SUBSTRING(@IPRange, 1, @SlashPos - 1);
DECLARE @PrefixBits INT = CAST(SUBSTRING(@IPRange, @SlashPos + 1, 2) AS INT);
DECLARE @IPAddressInt BIGINT =
PARSENAME(@IPAddress, 4) * POWER(CAST(2 AS BIGINT), 24) +
PARSENAME(@IPAddress, 3) * POWER(CAST(2 AS BIGINT), 16) +
PARSENAME(@IPAddress, 2) * POWER(CAST(2 AS BIGINT), 8) +
PARSENAME(@IPAddress, 1);
DECLARE @NetworkInt BIGINT =
PARSENAME(@Network, 4) * POWER(CAST(2 AS BIGINT), 24) +
PARSENAME(@Network, 3) * POWER(CAST(2 AS BIGINT), 16) +
PARSENAME(@Network, 2) * POWER(CAST(2 AS BIGINT), 8) +
PARSENAME(@Network, 1);
DECLARE @Mask BIGINT = POWER(CAST(2 AS BIGINT), 32) -
POWER(CAST(2 AS BIGINT), 32 - @PrefixBits);
RETURN CASE WHEN @IPAddressInt & @Mask = @NetworkInt THEN 1 ELSE 0 END;
END
使用例:
SELECT *
FROM IPAddressTable a
JOIN IPRangeTable r
ON dbo.IPAddressInRange(a.IPAddress, r.IPRange) = 1