在 SQL Server 存储过程中验证日期参数
Posted
技术标签:
【中文标题】在 SQL Server 存储过程中验证日期参数【英文标题】:Validating Date Parameter in SQL Server Stored Procedure 【发布时间】:2009-02-11 08:25:56 【问题描述】:我编写了一个接收日期参数的存储过程。我担心American
和British
日期格式之间会有混淆。确保日期之间没有歧义的最佳方法是什么,例如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 注入)动态 SQL?
将用户定义表中的日期值传递给 SQL Server 2008 存储过程