在 SQL Server 存储过程中验证日期参数

Posted

技术标签:

【中文标题】在 SQL Server 存储过程中验证日期参数【英文标题】:Validating Date Parameter in SQL Server Stored Procedure 【发布时间】:2009-02-11 08:25:56 【问题描述】:

我编写了一个接收日期参数的存储过程。我担心AmericanBritish 日期格式之间会有混淆。确保日期之间没有歧义的最佳方法是什么,例如02/12/2008。一种可能性是用户以20081202 (yyyymmdd) 等格式输入日期。有没有办法在不使用子字符串的情况下验证这一点?或者,日期可以输入为02-Dec-2008(dd-mmm-yyyy),但再次验证并非易事,不使用英语的用户可能会遇到问题。

在前三个答案的基础上。 . .一个问题是,我希望在没有前端的情况下直接调用这个存储的过程,因此在过程之外进行验证不是一种选择。将日、月和年作为单独的参数是否是个好主意?

【问题讨论】:

【参考方案1】:

如果您在存储过程中使用参数,则不会有任何问题:

create proc dbo.Sproc
    @date datetime
as
    ...

【讨论】:

我们已经在使用 datetime 类型,这个问题是根据用户的本地化设置,相同的有效日期时间输入可能具有不同的含义。 所以问题不在于 SQL,是吗?您应该正确解析表示层中的输入并将有效的日期时间传递给 SQL Server。 这个过程没有表现层。这就是为什么它是一个 SQL 问题。【参考方案2】:

如果您将参数声明为 DATETIME 类型或 SQL Server 中的其他类型的日期/时间类型之一,您应该这样做,那么就没有歧义;它代表特定的日期和时间。您所说的验证类型应该发生在存储过程之外,而不是内部。


从您的 cmets 确定并进行编辑,看来问题出在人们调用 SP 的方式上,而不是实际上在其中。为此,您只需要训练您的用户使用可排序的日期格式,即

yyyy-MM-dd HH:mm:ss

然后就没有歧义了。任何被允许接近数据库的人都应该注意本地化问题,并且在输入日期时应该始终使用类似这种明确的格式。

【讨论】:

存在歧义,因为日期的含义取决于本地化设置。例如。 2008 年 2 月 12 日对于英国人来说是 12 月 2 日,但在美国是 2 月 12 日。使用日期时间格式没有帮助,因为它在两种本地化中都是有效的日期。 A DATETIME 不存储为字符串,它存储为自一个纪元以来的多个间隔,因此数据类型本身没有歧义。无论如何,DATETIME 都不是 CHAR/VARCHAR。 您可能会感到困惑,因为它的打印结果因地区而异?但这只是打印出来的方式。 DATETIME 实际包含的数据没有歧义。 歧义在作为字符串输入的输入数据中。【参考方案3】:

我最终为日期获取了一个字符串参数,并要求用户输入月份作为单词。我通过将输入转换为日期来检查输入是否为有效日期。为确保月份以单词形式输入,我使用 like 比较器将输入字符串与“%Jan%”或“%Feb%”或“%Mar%”等进行比较。

【讨论】:

【参考方案4】:

如果您的 proc 接受日期作为日期时间参数,那么您几乎无法验证所需的格式是 ddmmyyyy 而不是 mmddyyyy。这完全取决于用户如何输入日期以及如何将日期传递给 SQL。

例如:在网页上我可以添加这样的参数

command.Parameters.AddWithValue("@mydate",mydateVar.ToString("dd/MM/yyyy"));

command.Parameters.AddWithValue("@mydate",mydateVar.ToString("MM/dd/yyyy"));

只要字符串可以正确地转换为日期,SQL 就会插入它给定的内容。它不会知道您要使用的格式,因此会尝试转换为系统默认格式。

我使用的一种解决方案(尽管它可能不适用于您的情况)是让用户以 dd-MMM-yyyy 格式在您拥有的任何前端中输入所有日期。然后我可以在插入数据库之前确定格式。我在任何地方都使用这种格式,以在整个应用程序中保持相同。

【讨论】:

【参考方案5】:

您说您希望在没有前端的情况下直接调用此存储过程,并且不能选择在过程之外进行验证。

在那种情况下用户将直接插入数据,我也相信在这种情况下它仅供内部使用(因为存储的过程将被直接调用)

所以我认为你有两个选择

    如果您有纪律严明的用户,您可以同意safe formats 之一:ISO yyyyddmm 或 ISO8601 yyyy-mm-dd Thh:mm:ss:mmm 如果您还需要时间部分 否则采用 3 个参数:年、月、年并在存储过程中执行一些验证

【讨论】:

感谢您的回答。你知道有什么方法可以检查日期是否以一种安全格式输入? 无论您做什么检查,您都无法确定当用户输入 20090211 时,他的意思是 2 月 11 日或 11 月 2 日,除非您清楚地传达格式。在您的代码中,您可以假设它是 iso 格式,如果返回错误,只需转换为 datetime 即可向用户显示错误消息 安全格式意味着在将字符串转换为日期时间类型时,SQL Server 将始终将字符串解释为 yyyyddmm,无论您的区域设置如何【参考方案6】:

我说要一个日期时间并训练他们使用 ODBC 规范的日期形式,如下例所示:

EXECUTE uspMyProc d '2009-02-11'

如果您需要解析一个日期,无论是字符串还是年、月和日作为单独的整数参数,那么您必须处理超出月和年范围的天数。一些功能可以让您在当天自动前进或后退。因此,当天发送 0 并获取上个月的最后一天的技巧。其他人返回错误。但是自己处理这些东西可能不值得重新发明***。

如果您绝对必须这样做,因为新手将直接运行它(为什么新手会直接运行存储过程?),我将采用三个单独的参数并将连接的日期作为格式为 YYYY-MM-DD 的字符串传递通过ISDATE验证参数,如果无效则退出。

【讨论】:

以上是关于在 SQL Server 存储过程中验证日期参数的主要内容,如果未能解决你的问题,请参考以下文章

将 Access 表日期值作为参数传递给 SQL Server 存储过程

SQL Server 日期格式不适用于存储过程

如何在 SQL Server 中清理(防止 SQL 注入)动态 SQL?

将用户定义表中的日期值传递给 SQL Server 2008 存储过程

插入前Microsoft SQL Server转换中的存储过程

SQL Server 2005 使用 GETDATE() 作为参数通过 SSIS 运行存储过程