1

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

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

我想使用正则表达式来做到这一点,但默认情况下似乎不支持此功能。我看到了关于在里面写一个带有 UDF 的 customm dll 的事情(MSDN 教程),但我真的不明白它是如何工作的(即我应该将 dll 放在哪里?)

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

提前致谢 !

4

6 回答 6

2

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

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

正如其他人所说,这最好在插入数据库之前由应用程序处理。

于 2010-07-29T13:16:33.850 回答
1

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

然后向数据库添加检查并没有什么害处,但是将其留给数据库来过滤输入是非常粗略的。

于 2010-07-29T13:12:25.230 回答
1

我能想到的最简单的方法是创建一个类似的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')
于 2010-07-29T13:33:40.290 回答
1

此解决方案类似于Paulo 的解决方案,但使用任何一种方法都需要去掉逗号字符,因为 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')
于 2015-06-05T18:11:45.677 回答
0

这可能并不完全实用,但一种方法是将转换后的字符串 ###-###-###-### 存储到 binary(4) 数据类型中。让界面用连字符大惊小怪,并处理将四个数字转换为二进制并返回(这甚至可以通过计算列来完成。)有点极端,是的,但是使用 binary(4) 你总是能够把它变成一个IP地址。

于 2010-07-29T13:44:27.600 回答
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 等......

于 2018-12-14T10:36:33.087 回答