【问题标题】:SQLite database with C# Unable to compare datetime datatype使用 C# 的 SQLite 数据库无法比较日期时间数据类型
【发布时间】:2016-06-20 02:39:30
【问题描述】:

我正在使用 C# (.NET) 和 SQLite 数据库。 我在 SQLite 数据库中有一个表,其中有一列名为“InvoiceDate”。我选择了与 TEXT 相同的数据类型(在 db 表中),因为我需要它作为日期时间变量。

我正在使用System.Data.SQLite reference

以下是我遇到问题的命令文本:

command.CommandText = "SELECT * FROM InvoiceMaster WHERE InvoiceDate BETWEEN '" 
                     + date1.ToString() + "' AND '" 
                     + date2.ToString() + "' ORDER BY InvoiceNumber";

我需要查找 InvoiceDate 列介于给定日期 date1 和 date2 之间的所有结果。但问题是,即使我选择了其他日期,我也会得到结果,例如,即使我选择了不同的年份,我也会在同一个月份和日期得到相同的结果。命令文本有问题,我还需要知道我应该在 db 表中选择什么类型的数据类型。请让我知道我应该如何编写选择命令。

【问题讨论】:

  • Possible SQL Injection 使用准备好的语句/参数绑定,你的问题就迎刃而解了。
  • 能否给我一个示例代码...
  • 你先做基础研究了吗?您在提供的链接中有示例
  • 只是想在谷歌中找到它.....
  • 您需要正确格式化日期字符串...

标签: c# database sqlite datetime


【解决方案1】:

您可以创建一个方法来转换您的日期时间

 private string DateTimeSQLite(DateTime datetime)
  {
    string dateTimeFormat = "{0}-{1}-{2} {3}:{4}:{5}.{6}";
    return string.Format(dateTimeFormat, datetime.Year,   
                         datetime.Month,datetime.Day, 
                         datetime.Hour, datetime.Minute,  
                          datetime.Second,datetime.Millisecond);
  }

或者更好的让它成为一个扩展方法。

 private static string DateTimeSQLite(this DateTime datetime)
 {}

同时使用参数化查询来避免 sql 注入

string commandText = "SELECT * FROM InvoiceMaster 
                  WHERE InvoiceDate BETWEEN @date1 and @date2
                  ORDER BY InvoiceNumber"
yourcommand.Parameters.Add("@date1",date1.DateTimeSQLite());
yourcommand.Parameters.Add("@date2",date1.DateTimeSQLite());

【讨论】:

  • 我认为这不是一个好主意,因为单个数字的月、日、小时、分钟和秒部分不会有前导零。
【解决方案2】:

来自1.2 Date and Time Datatype

TEXT 作为 ISO8601 字符串 ("YYYY-MM-DD HH:MM:SS.SSS")

由于ToString()不会生成这种格式,所以可以使用自定义格式如;

date1.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture)
date2.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture)

但更重要的是,您应该始终使用parameterized queries。这种字符串连接对SQL Injection 攻击开放。

我对格式不是 %100,但您可能想使用The "o" standard format specifier 代表;

.. 使用保留模式的自定义日期和时间格式字符串 时区信息并发出符合 ISO 的结果字符串 8601.

command.CommandText = @"SELECT * FROM InvoiceMaster 
                        WHERE InvoiceDate BETWEEN @date1 AND @date2 
                        ORDER BY InvoiceNumber";

command.Parameters.AddWithValue("@date1", date1.ToString("o"));
command.Parameters.AddWithValue("@date2", date1.ToString("o));

【讨论】:

  • 这很有趣,因为ISO 8601 的格式为 yyyy-mm-ddThh:mm:ss[.mmm]。 SQLite 文档指出T 不是本标准的一部分。
  • ISO 8601 与文化无关。但不是 SQLite 文档中提供的格式。请检查demo并更正一个demo2
  • @lad2025 你说得有道理,但我写了这种格式,因为文档是这样说的。我从来没有诚实地使用过 Sqlite,这就是为什么我不确定 %100。
  • 尝试了以下操作:command.CommandText = "SELECT * FROM InvoiceMaster WHERE InvoiceDate BETWEEN 'DATETIME(" + date1.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo. InvariantCulture) + ")' AND 'DATETIME(" + date2.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture) + ")'";还是不行
  • @SlickGuy 我更新了我的答案。你能看一下吗?
【解决方案3】:

由于您已选择将日期存储为数据库中的TEXT 字段,因此必须使用 ISO8601 对其进行格式化。示例:

2016-02-03T20:34:22Z

因此,一旦您确保它们以这种方式存储,剩下的就是对您的查询进行参数化:

DateTime date1 = ... get from somewhere
DateTime date2 = ... get from somewhere

using (var conn = new SQLiteConnection("Data Source=mydb.db;Version=3;"))
using (var cmd = conn.CreateCommand())
{
    conn.Open();
    cmd.CommandText = "SELECT * FROM InvoiceMaster WHERE InvoiceDate BETWEEN @startDate AND @endDate";
    cmd.Parameters.AddWithValue("@startDate", date1.ToString("o"));
    cmd.Parameters.AddWithValue("@endDate", date2.ToString("o"));
    using (var reader = cmd.ExecuteReader())
    {
        while (reader.Read())
        {
            // do something with the results here
        }
    }
}

请注意我如何使用.ToString("o") 格式说明符来确保将日期正确传递到数据库。

【讨论】:

    猜你喜欢
    • 2020-10-09
    • 1970-01-01
    • 2014-04-02
    • 1970-01-01
    • 2021-08-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多