【问题标题】:select where date (only date from datetime)选择日期(仅日期时间中的日期)
【发布时间】:2017-01-08 03:11:51
【问题描述】:

如何从日期格式 dd/mm/yyyy h:mm:ss 中搜索日期为 dd/mm/yyyy 的数据库(sql server)中的记录。

如果该列是日期,它可以正常工作,但是当我将它设为日期时间并想查看特定日期的数据库中是否有记录时,它会有所不同,因为有时间。

那么我怎样才能仅在列是日期时间时搜索日期。

这是我正在使用的:

    If SQL.conn.State = ConnectionState.Open Then
        SQL.conn.Close()
    End If
    DateTime1.Format = DateTimePickerFormat.Custom
    DateTime1.CustomFormat = "yyyy/MM/dd"

    SQL.conn.Open()
    Dim cmd As New SqlCommand("Select count(eid) from employees_payroll WHERE eid=" & employee_id & " and wday= '" & DateTime1.Text & "'", SQL.conn)
    count = Convert.ToInt32(cmd.ExecuteScalar())
    SQL.conn.Close()
    DateTime1.CustomFormat = "yyyy-MM-dd"

【问题讨论】:

  • 这段代码很容易受到sql注入攻击。它实际上是在乞求被黑。
  • 那么实现这一目标的最佳方法是什么?我正在使用此代码从表中获取行数,因此如果行数 > 0,那么我将向用户显示他已经添加了这个。
  • employees_payroll 表中 wday 的数据类型是什么?
  • 现在是日期,但我想将其设为日期时间,并仅从日期开始搜索。

标签: sql-server vb.net


【解决方案1】:

几种解决方案。将 datetime 转换为 date 这消除了时间

 Select * from table where cast (column as Date) = '1 jan 2017'

其次,使用日期差异功能

 Select * from table where datediff(day, column, '1Jan2017') = 0

第三,使用 datediff 和 dateadd 去除时间部分

 Select * from table 
 where dateadd(day, datediff(day, 0, column), 0) = '1Jan2017'

另外,比较一天开始和结束时的午夜

 Select * from table 
 where column >= '1 Jan 2017'
    and column < '2 jan 2017'

最后一个解决方案只允许在日期列上使用索引

编辑(解决乔尔在 cmets 提出的问题): 请理解,您用于将此查询传递给服务器的 C# 代码容易受到所谓的“SQL 注入”的攻击。如果您的应用程序正在从不受信任的用户的输入中构建此 SQL,那么这将是一场灾难。作为乔;在他下面的回答中建议,应该修改 C# 代码以使用具有定义参数的命令对象,而不是动态构造的 SQL。但是,SQL 语句本身仍然可以是上面建议的任何解决方案。

【讨论】:

  • 所有这些仍然鼓励使用字符串连接,这不是将数据放入 sql 命令的好方法。
  • @JoelCoehoorn 我们不知道 OP 的使用上下文。可能只是一个个人家庭项目,除了 OP 之外不向任何人公开,或者只是学校的学术课程,因此防黑客不在问题范围内。如果你是反对者,请重新考虑不要惩罚查尔斯没有解决没有被问到的问题。
  • @Joel Coehoorn ,这是个人项目,其本地项目不在互联网上或共享,但如果你能告诉我正确的方式,我会很高兴。谢谢
  • 不使用字符串连接的原因有很多。安全性只是其中之一,尽管可能是最重要的。在这里,参数化查询还具有修复他的格式问题的好特性。
  • @Joel,我想知道你误读了什么。这些都与字符串无关,除了表示目标日期的字符串文字。什么,你到底在说什么?你是在评论我对日期与日期时间问题的解决方案,还是对他的 vb.net 代码(我的解决方案没有解决)?
【解决方案2】:
Using cn  As New SqlConnection("connection string here"), _
      cmd As New SqlCommand("Select count(eid) from employees_payroll WHERE eid= @employee_id and wday >= @wday and wday < DATEADD(dd, 1, @wday)", cn)

    cmd.Parameters.Add("@employee_id", SqlDbType.Int).Value = Convert.ToInt32(employee_id)
    cmd.Parameters.Add("@wday", SqlDbType.DateTime).Value = DateTime1.Value

    cn.Open()
    count = Convert.ToInt32(cmd.ExecuteScalar())
End Using

关于这段代码的一些注释

在 .Net 中,您确实希望为大多数操作使用全新的连接对象。尝试在整个应用程序中重复使用相同的连接对象是错误的。真的。 SQL Server 的 ADO.Net 提供程序使用称为连接池的东西,当您在应用程序中坚持使用相同的对象时,您将失去它的好处。无需共享公共连接对象,只需共享一个公共连接字符串,以便在需要时创建新对象。然后你也可以将东西包装在Using 块中,这样即使抛出异常,这个连接也会根据需要正确关闭。请注意,在此示例中我不必cn.Close(),这不是错误。 Using妥善处理此问题。

不要使用字符串连接将数据值放入 sql 命令语句中!几个原因,从性能(你得到执行计划重新使用和更好的查询统计信息)到安全性(不再有 sql 注入漏洞!)到修复格式问题,就像你在这里遇到的一样。即使这看起来像是私有的 winforms 应用程序,而不是公共的 Web 应用程序,您仍然需要为此使用参数化查询。

当您开始在数据库中使用DateTime 值时,您的列值中有always 一个时间组件,Sql Server always 使用完整的比较这些值日期和时间,没有例外。如果不指定时间,Sql Server 使用“0”时间值,表示午夜。因此,比较DateTime 列中的两个“日期”仅在比较的双方 具有完全相同的时间值时才有效。如果您想知道 DateTime 值是否落在特定日期,正确的方法是检查它是否大于或等于当天的开始时间并且小于第二天的开始时间。如果您愿意,可以改为将您的 wday 列转换为该查询的 Date 类型。我鼓励您不要这样做,因为它会阻止 Sql Server 使用该列可能存在的任何索引。

【讨论】:

  • 谢谢,这很有帮助,所以最好的方法是始终使用参数??
  • 是的。始终为用户提供的查询中包含的任何内容使用参数,甚至包括您的应用程序可能提供的某些内容,例如日期或枚举值。
猜你喜欢
  • 2019-04-04
  • 2013-10-02
  • 2018-12-02
  • 1970-01-01
  • 2015-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多