检查约束以验证IP地址字段

时间:2010-07-29 13:06:23

标签: sql-server-2008 check-constraints

我正在开发一个涉及C#和SQL Server 2008数据库的项目。 在其中一个表中,我有一个字段(nvarchar(15)),其中包含一个IP地址。

我想添加一个检查约束,它将验证输入值实际上是一个IP地址。

我想使用正则表达式来执行此操作,但默认情况下似乎不支持此功能。我看到了用UDF编写自定义dll的内容(MSDN tutorial),但我真的不明白它是如何工作的(即我应该在哪里放置dll?)

是否有一种“简单”的方式来添加这样的约束? 欢迎任何解决方案。

提前致谢!

6 个答案:

答案 0 :(得分:2)

有几种方法可以做到这一点 - 数据库中性能最高的可能是CLR function

这是因为SQL的文本操作工具相当差,SQL Server中没有本机RegEx。

正如其他人所说,在插入数据库之前,应用程序可以更好地处理这个问题。

答案 1 :(得分:2)

我能想到的最简单的方法是创建一个像fnCheckIP这样的函数,并在约束中使用这个函数。

无需使用UDF。

create function fnCheckIP(@ip varchar(15)) returns bit
AS
begin
    if (@ip is null)
        return null

    declare @num1 int
    declare @num varchar(15)    
    declare @pos int
    while (@ip is not null)
    begin
        set @pos = IsNull(NullIf(charindex('.', @ip), 0), Len(@ip) + 1)
        set @num = substring(@ip, 1, @pos - 1)

        if (isnumeric(@num) = 0) or (not cast(@num as int) between 0 and 255)
            return cast(0 as bit)

        if (len(@ip) - @pos <= 0)
            set @ip = null
        else        
            set @ip = NullIf(substring(@ip, @pos + 1, len(@ip) - @pos), '')
    end

    return cast (1 as bit)
end
go

select dbo.fnCheckIP('127.0.0.1')
select dbo.fnCheckIP('127.0.0.300')

答案 2 :(得分:1)

不应该在数据库中处理它,应该首先在应用程序中处理它。

然后在数据库中添加一个检查没有什么坏处,但是将它留给DB来过滤输入是非常粗略的。

答案 3 :(得分:0)

这可能不完全实用,但一种方法是将转换后的字符串### - ### - ### - ###存储到二进制(4)数据类型中。让接口用连字符乱七八糟地处理将四个数字转换成二进制数并返回(这甚至可能由一个caluclated列完成。)有点极端,是的,但是使用二进制(4)你将总是能够将其转换为IP地址。

答案 4 :(得分:0)

此解决方案与Paulo's类似,但使用任何一种方法都需要删除逗号字符,因为isnumeric允许使用逗号将强制转换为int错误。

CREATE FUNCTION fn_ValidateIP
(
    @ip varchar(255)
)
RETURNS int
AS
BEGIN
    DECLARE @Result int = 0
        IF
            @ip not like '%,%' and
            len(@ip) <= 15 and
            isnumeric(PARSENAME(@ip,4)) = 1 and
            isnumeric(PARSENAME(@ip,3)) = 1 and
            isnumeric(PARSENAME(@ip,2)) = 1 and
            isnumeric(PARSENAME(@ip,1)) = 1 and
            cast(PARSENAME(@ip,4) as int) between 1 and 255 and
            cast(PARSENAME(@ip,3) as int) between 0 and 255 and
            cast(PARSENAME(@ip,2) as int) between 0 and 255 and
            cast(PARSENAME(@ip,1) as int) between 0 and 255
            set @Result = 1
        ELSE
            set @Result = 0
    RETURN @Result
END

select dbo.fn_ValidateIP('127.0.0.1')

答案 5 :(得分:0)

在Oracle之后大约10年,sqlserver获得了本机编译(有限制)

    ALTER function fn_ValidateIPv4
(
@ip varchar(255)
)
RETURNS int
--WITH EXECUTE AS OWNER, SCHEMABINDING, NATIVE_COMPILATION  
AS
BEGIN 
--ATOMIC WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english')
/* only sql2016 native Compilation **/
DECLARE @len_ip as int;
SET @len_ip =  len(@ip);
DECLARE @firstBlock varchar(4) = '';
DECLARE @secondBlock varchar(4) = '';
DECLARE @thirdBlock varchar(4) = '';
DECLARE @fourthBlock varchar(4) = '';
DECLARE @countDot as smallint = 0;
DECLARE @l_i as smallint = 0;

DECLARE @l_curChar varchar(1) = 'X';

DECLARE @Result int = 0
    IF (@len_ip <= 15)
    BEGIN
        WHILE (@l_i < @len_ip) 
        BEGIN
            set @l_i += 1;
            set @l_curChar = substring(@ip,@l_i,1);
            if @l_curChar = '.'
                SET @countDot += 1
            ELSE
            BEGIN
                IF @l_curChar IN ( '0','1','2','3','4','5','6','7','8','9' )
                BEGIN
                    IF @countDot = 0 
                        SET @firstBlock = @firstBlock + @l_curChar;
                    IF @countDot = 1
                        SET @secondBlock = @secondBlock + @l_curChar;
                    IF @countDot = 2
                        SET @thirdBlock = @thirdBlock + @l_curChar;
                    IF @countDot = 3
                        SET @fourthBlock = @fourthBlock + @l_curChar;
                    IF  @countDot > 3
                        set @firstBlock = 'AAA'; -- force error 
                END
                ELSE set @firstBlock = 'AAA'; -- force error                

            END;
        END;            

        IF ( @countDot = 3 and
            cast(@fourthBlock as int) between 1 and 255 and
            cast(@thirdBlock as int) between 0 and 255 and
            cast(@secondBlock as int) between 0 and 255 and
            cast(@firstBlock as int) between 0 and 255 
            )           
            set @Result = 1;
    END;

    /*
    select dbo.fn_ValidateIPv4( '127.0.0.258' );        
    */
RETURN @Result
END;

我必须删除不支持的内置函数isnumeric等...