【问题标题】:Python's Sqlite3 module will not return full rows when using SELECT FROM WHERE使用 SELECT FROM WHERE 时 Python Sqlite3 模块不会返回所有行
【发布时间】:2020-06-16 04:35:10
【问题描述】:

我正在尝试使用 Python 的 Sqlite3 模块创建一个函数,该模块将根据使用 SELECT 命令的日期时间时间戳搜索返回行列表。

现在,选择所有内容(使用'select * from example_table')将正确返回整行,但基于时间戳进行选择(使用'''select %s from %s where %s > ? and %s < ?''' % (date_col_name, table_name, date_col_name, date_col_name))只会返回元组中的时间戳(缺少另一列)。

以前,我努力保留 datetime 数据类型,但使用 detect_types=sqlite3.PARSE_DECLTYPES 它会返回一个实际的 datetime 对象。通常我会怀疑这是问题所在,但是 SELECT 命令的实际“过滤”部分正在工作。 正在返回正确的日期时间对象,它们只是缺少它们所属行中的其他数据。

相关代码:

sql_database_name = 'data_history.db'
date_col_name = 'Date'

class Database manager ...

    ... init ...

    def get_table_range(self, table_name, daterange=None):
        con = sqlite3.connect(self.database_name, detect_types=sqlite3.PARSE_DECLTYPES)
        c = con.cursor()

        if daterange is not None:
            startdate = daterange[0]
            enddate = daterange[1]
            sql = '''select %s from %s where %s > ? and %s < ?''' % (date_col_name, table_name, date_col_name, date_col_name)
            data = (startdate, enddate)
            c.execute(sql, data)
        else:
            sql = 'select * from %s' % table_name
            c.execute(sql)

        print("Fetchine one: ", c.fetchone())

        result = c.fetchall()

        c.close()
        con.close()

        return result


if __name__ == "__main__":
    test_db = "test.db"
    manager = DatabaseManager(database_name=test_db)

    selected = manager.get_table_range("test_table")
    print("Selected " + str(len(selected)) + "rows.")

    print("---")

    selected = manager.get_table_range("test_table", (datetime(2020, 3, 2, 23), datetime(2020, 3, 3)))
    print("Selected " + str(len(selected)) + "rows.")

实际输出:

Fetchine one:  (datetime.datetime(2020, 3, 2, 19, 12, 57, 120184), 291.0)
Selected 97rows.
Fetchine one:  (datetime.datetime(2020, 3, 2, 23, 22, 15, 704786),) <<-- extra columns were not returned
Selected 25rows.

期望的输出:

Fetchine one:  (datetime.datetime(2020, 3, 2, 19, 12, 57, 120184), 291.0)
Selected 97rows.
Fetchine one:  (datetime.datetime(2020, 3, 2, 23, 22, 15, 704786), XXX.X) 
Selected 25rows.

【问题讨论】:

标签: python sql database sqlite datetime


【解决方案1】:

它返回的正是您所要求的,因为您的查询转换为:

 SELECT date_col_name FROM table_name WHERE date_col_name < ? AND date_col_name > ?;

您可能想要生成代码SELECT * FROM. . .SELECT list, of, column, names FROM . . .

为什么要使用字符串替换列和表名来构建 SQL 语句?你应该只是写:

 sql = '''select date_col_name from table_name where date_col_name > ? and date_col_name < ?''' 

列名不是变量(除非您对多个具有不同名称和不同列名的结构相同的表进行了一些奇怪的设置,这可能表明存在设计缺陷)。

【讨论】:

  • 你的最后一句话正是我设置的。在一个小型网络中,我有许多小型微控制器(ESP8266)从给定空间的各个点发送温度数据。我有每个传感器的表和每个表的 datetime + temp 列,每个表都以每个传感器命名。这些传感器不会以相同的时间间隔进行测量,所以我认为我不能将它们包含在同一张表中。有没有更好的方法让你眼前一亮?
  • 我被告知名称/常量不应该是“硬编码”。如果我以后需要更改它们,我只需要编辑一行。这不是 SQL 的情况吗?我很感激这些提示!这正是我问的原因,我对 SQL/数据库很陌生。
  • 当我对你的应用程序的信息知之甚少时,我会擅自决定你的应用程序的设计。也就是说:-),我的强烈倾向是CREATE TABLE Measurements (SensorID TEXT, MeasureWhen DATETIME, Temperature REAL)。如果每个传感器的间隔对您很重要(例如,如果同一应用程序实际控制传感器),我将有一个附加表 CREATE TABLE Sensors (SensorID TEXT, IntervalInSeconds INT)。我想无论如何我都会有那个表来验证 SensorID。
  • 如果我想每隔几秒拉出一个特定的数据区域来绘制图表,这种方法不会大大减慢查找时间吗?或者索引(诚然,这是我学习数据库的下一个主题)在很大程度上解决了这个问题?我最初创建单独表格的动机是,我可以减少稍后在获取某个时间范围内的传感器历史记录时筛选的数据量。
  • 索引在很大程度上解决了这个问题。正确设计数据库。如果您以后遇到性能问题(例如,当您达到 1 亿次左右的测量值时),您可以考虑“分片”数据以提高性能——只有当这种情况发生时,您才能获得有关性能问题所在位置的实用信息.
猜你喜欢
  • 2014-09-02
  • 2013-11-04
  • 2021-06-08
  • 2016-11-17
  • 1970-01-01
  • 2014-06-17
  • 2020-12-10
  • 2018-07-04
  • 1970-01-01
相关资源
最近更新 更多