我在将日期值插入SQL查询时遇到问题。我正在使用sqlite3和python。查询是:
c.execute("""SELECT tweeterHash.* FROM tweeterHash, tweetDates WHERE
Date(tweetDates.start) > Date(?) AND
Date(tweetDates.end) > Date(?)""",
(start,end,))
查询不返回任何值,并且没有错误消息。如果我使用此查询:
c.execute("""SELECT tweeterHash.* FROM tweeterHash, tweetDates WHERE
Date(tweetDates.start) > Date(2014-01-01) AND
Date(tweetDates.end) > Date(2015-01-01)""")
然后我得到了我想要的值,这是预期的吗?
值start和end来自文本文件:
f = open('dates.txt','r')
start = f.readline().strip('\n')
end = f.readline().strip('\n')
但我也尝试过宣布它:
start = '2014-01-01'
end = '2015-01-01'
我想我不明白为什么从开头和结尾变量传入字符串并不起作用?将日期变量传递给SQL查询的最佳方法是什么?任何帮助是极大的赞赏。
答案 0 :(得分:2)
这些日期并不相同 - 而且是您错误的非参数化日期。
Date(2014-01-01)
计算算术表达式2014 - 01 - 01
,然后从结果数Date
构造2012
,这将在公元前4707年为您提供一些东西。
Date('2014-01-01')
或Date(?)
,其中参数为字符串'2014-01-01'
,构建了2014年AD所需的日期。
只需直接选择日期即可更轻松地看到这一点:
>>> cur.execute('SELECT Date(2014-01-01), Date(?)', ['2014-01-01'])
>>> print(cur.fetchone())
('-4707-05-28', '2014-01-01')
同时
将日期变量传递给SQL查询的最佳方法是什么?
理想情况下,使用实际日期对象而不是字符串。 sqlite3
库知道如何处理datetime.datetime
和datetime.date
。并且不要在值上调用Date
,只需比较它们即可。 (是的,sqlite3可能会将它们比作字符串而不是日期,但是使用类似ISO8601的格式的全部意义在于它总是会给出相同的结果......除非你有一堆公元前4707年左右的日期。)所以:
start = datetime.date(2014, 1, 1)
end = datetime.date(2015, 1, 1)
c.execute("""SELECT tweeterHash.* FROM tweeterHash, tweetDates WHERE
tweetDates.start > ? AND
tweetDates.end > ?""",
(start,end,))
这也意味着当我创建表格时,我想要:“开始日期时间,结束日期时间”,?
那会有用,但我不会这样做。 Python会将date
个对象转换为ISO8601格式的字符串,但不会转换回SELECT
,SQLite会让您透明地将这些字符串与Date
函数返回的值进行比较。
您可以使用TEXT
获得相同的效果,但我相信您会发现它不那么令人困惑,DATETIME
会将列关联设置为NUMERIC
,这可能会混淆人类和当你实际存储字符串时的其他工具。
或者您可以使用类型DATE
- 这对SQLite和DATETIME
一样没有意义,但它可以告诉Python透明地将返回值转换为datetime.date
个对象。请参阅sqlite3
文档中的Default adapters and converters。
此外,如果您还没有阅读Datatypes in SQLite Version 3和SQLite and Python types,那么您真的应该这样做;有很多东西都令人惊讶(甚至 - 或者尤其是 - 如果你使用过其他数据库),并且可能非常有用。
与此同时,如果您认为通过传递Date(2014-01-01)
获得了“正确”的结果,那么这意味着您实际上已经在数据库中获得了大量垃圾值。并且没有办法解决它们,因为错误是不可逆的。 (毕竟,2014-01-01和2015-01-02都是2012 ...)希望您不需要旧数据,或者可以重新生成它。否则,您需要某种解决方法,以便在这种情况下尽可能有用地处理现有数据。