我正在开发一个涉及C#和SQL Server 2008数据库的项目。
在其中一个表中,我有一个字段(nvarchar(15)
),其中包含一个IP地址。
我想添加一个检查约束,它将验证输入值实际上是一个IP地址。
我想使用正则表达式来执行此操作,但默认情况下似乎不支持此功能。我看到了用UDF编写自定义dll的内容(MSDN tutorial),但我真的不明白它是如何工作的(即我应该在哪里放置dll?)
是否有一种“简单”的方式来添加这样的约束? 欢迎任何解决方案。
提前致谢!
答案 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等...