Sql server SQL Server代码为;“消毒”;用户输入到可行的数据格式

Sql server SQL Server代码为;“消毒”;用户输入到可行的数据格式,sql-server,regex,user-input,sanitize,Sql Server,Regex,User Input,Sanitize,我正在MS SQL Server中创建一个函数,该函数允许报表开发人员从用户输入字段获取数据,并将其转换为可行的数据格式。99%的时候,我正在使用的代码,下面,工作。然而,用户总是想方设法把他们应该输入的数据搞砸(我在一家拥有数千名入门级数据输入员工的大公司工作) 我主要要解决的问题是将非常糟糕的用户输入,如“$100000..411”转换为可行的十进制格式。我希望它变成‘100000.41’(因为这是我们最接近了解用户在输入时的想法),但我下面使用的代码只会把它变成‘100000..411’

我正在MS SQL Server中创建一个函数,该函数允许报表开发人员从用户输入字段获取数据,并将其转换为可行的数据格式。99%的时候,我正在使用的代码,下面,工作。然而,用户总是想方设法把他们应该输入的数据搞砸(我在一家拥有数千名入门级数据输入员工的大公司工作)

我主要要解决的问题是将非常糟糕的用户输入,如“$100000..411”转换为可行的十进制格式。我希望它变成‘100000.41’(因为这是我们最接近了解用户在输入时的想法),但我下面使用的代码只会把它变成‘100000..411’

这是到目前为止我已经完成的代码。它允许报表开发人员选择要返回的数据类型,还允许传递自定义正则表达式:

CREATE FUNCTION dbo.udf_FieldSanitizer
     (
     @String VARCHAR(250)
     ,@Datatype VARCHAR(250)
     )
RETURNS VARCHAR(250)
AS
BEGIN
     DECLARE @Expression VARCHAR(10)
     SELECT
           @Expression =   CASE
                                WHEN @Datatype = '1' THEN '^0-9-'
                                WHEN @Datatype = '2' THEN '^0-9.-'
                                WHEN @Datatype = '3' THEN '^a-z'
                                WHEN @Datatype = '4' THEN '^a-z '
                                WHEN @Datatype = '5' THEN '^a-z ,'
                                WHEN @Datatype = '6' THEN '^a-z0-9'
                                WHEN @Datatype = '7' THEN '^a-z0-9 '
                                WHEN @Datatype = '8' THEN '^a-z0-9 ,'
                                ELSE @Datatype
                                END

     WHILE PATINDEX('%['+@Expression+']%',@String) > 0
           SET @String = STUFF(@String,PATINDEX('%['+@Expression+']%',@String),1,'')

     RETURN @String

END

好的,为了简单地回答您的问题并继续讨论您希望如何执行此操作,我建议在您执行选择之前添加一个检查并替换@String,类似这样:

     DECLARE @Expression VARCHAR(10)
     IF @Datatype = '2'
         AND (SELECT LEN(@String) - LEN(REPLACE(@String,'.',''))) > 1
         SET @String = REPLACE(@String,'..','.')
     SELECT
           @Expression =   CASE
另一方面,您的@Datatype被定义为VARCHAR(150),但您似乎在使用数字。如果是这样,我会将其改为SMALLINT或TINYINT,但这是另一篇文章(以及您通常应该如何避免使用标量函数)


此外,只要你必须处理自由文本,你就会不断地添加这些类型的错误处理条款(用户会找到独特的方法来打破这些条款),这就是为什么最好像FLICKER所建议的那样将其保留在UI级别。

好吧,简单地回答你的问题,然后继续讨论你想怎么做,我建议在进行选择之前添加一个复选框并替换@String,如下所示:

     DECLARE @Expression VARCHAR(10)
     IF @Datatype = '2'
         AND (SELECT LEN(@String) - LEN(REPLACE(@String,'.',''))) > 1
         SET @String = REPLACE(@String,'..','.')
     SELECT
           @Expression =   CASE
另一方面,您的@Datatype被定义为VARCHAR(150),但您似乎在使用数字。如果是这样,我会将其改为SMALLINT或TINYINT,但这是另一篇文章(以及您通常应该如何避免使用标量函数)



此外,只要你必须处理自由文本,你就会不断地添加这些类型的错误处理条款(用户会找到独特的方法来打破这些条款),这就是为什么它最好像FLICKER建议的那样留在UI级别。

你是否在努力将“1000…0.411”剪切为“1000…0.41”?如果是,请使用该函数。我不确定我是否完全理解你的目标。你不需要一些通用的包装器,开发者可以在其中传递正则表达式吗?那么包装器的用途是什么?用户如何输入数据?如果他们使用的是UI,难道你不能在UI级别进行验证吗?我认为你不想在数据库级别进行清理,你想在该层拒绝任何坏数据。用户可能永远也不会知道您已经更改了他们输入的内容,并且最终可能会存储坏的/无用的数据。我同意@FLICKER-用户界面应该尽量减少数据库提供的拒绝。我的2¢我不反对在前端完成,但是,我是DBA,无法控制SOR的前端。相反,我一直在处理糟糕的数据,并尽力帮助数据分析师处理数据。我已经提过好几次了,当你在像我这样的大公司工作(员工总数超过25万)时,即使是这样的小努力也不会被优先考虑。你是否在努力将“1000…0.411”削减为“1000…0.41”?如果是,请使用该函数。我不确定我是否完全理解你的目标。你不需要一些通用的包装器,开发者可以在其中传递正则表达式吗?那么包装器的用途是什么?用户如何输入数据?如果他们使用的是UI,难道你不能在UI级别进行验证吗?我认为你不想在数据库级别进行清理,你想在该层拒绝任何坏数据。用户可能永远也不会知道您已经更改了他们输入的内容,并且最终可能会存储坏的/无用的数据。我同意@FLICKER-用户界面应该尽量减少数据库提供的拒绝。我的2¢我不反对在前端完成,但是,我是DBA,无法控制SOR的前端。相反,我一直在处理糟糕的数据,并尽力帮助数据分析师处理数据。我已经提过好几次了,当你在像我这样的大公司工作时(员工总数超过25万),即使是这样的小努力也不会被优先考虑。我定义了一些预设表达式,用户只需使用1-8就可以通过,但是他们也可以传递自己的自定义表达式,以便在需要删除或包含我没有预定义的其他类型的数据时使用。是的,我看到了1-8和相关的正则表达式,这就是我使用@Datatype='2'的原因。那么,上述方法是否可以删除十进制中的重复句点呢?不幸的是,没有,这是我创建此线程的最大原因之一。我在金融部门工作,而货币记录是我们存储数据的重要部分。大量的计算都是在这些货币上进行的,如果它们的格式不正确,工作就会失败。现在,我们事先做一个ISNUMERIC检查,以防止坏数据出错,但我不喜欢这样做,因为这样做时我们会忽略这些行项目。我希望我的函数能更进一步,将“$1234..45.”之类的东西转换成一种可行的格式。所以你的问题是:我主要要做的是将非常糟糕的用户输入,如“$100000..411”转换成一种可行的十进制格式。上面的IF语句就是这样做的,所以我对您要查找的内容感到困惑。这只解决了一行中两个小数的非常具体的情况,这只是一个示例。如果字符串是与“100.1.14”类似的内容,则它不会解决问题。我越是考虑我在寻找什么,我就越认为它不可能。我定义了一些用户可以通过JU通过的预置表达式。