【问题标题】:Querying postgresql from Python for DateTime values between two dates从 Python 查询 postgresql 以获取两个日期之间的 DateTime 值
【发布时间】:2016-08-29 18:17:32
【问题描述】:

我在 Postgres 表中有以下 dateTime 文本类型变量

"2016-05-12T23:59:11+00:00"          
"2016-05-13T11:00:11+00:00"
"2016-05-13T23:59:11+00:00"
"2016-05-15T10:10:11+00:00"
"2016-05-16T10:10:11+00:00"
"2016-05-17T10:10:11+00:00"

我必须编写一个 Python 函数来提取两个日期之间一些变量的数据

def fn(dateTime):
    df1=pd.DataFrame()
    query = """ SELECT "recordId" from "Table" where "dateTime" BETWEEN %s AND %s """ %(dStart,dEnd) 
    df1=pd.read_sql_query(query1,con=engine)
    return df1

我需要创建 dStart 和 dEnd 变量并将它们用作函数参数,如下所示

   fn('2016-05-12','2016-05-15')

我尝试使用 to_char("dateTime", 'YYYY-MM-DD') Postgres 函数,但没有成功。请告诉我如何解决这个问题

【问题讨论】:

  • 请检查函数定义,它有一个参数,而您正在使用2个值调用该函数。
  • dateTime 列是定义为text 还是timestamp with timezone?如果可以的话,我强烈建议为此使用时间戳列。

标签: python postgresql datetime pandas


【解决方案1】:

使用 sql 时,您应该始终使用 sql 库将参数替换到查询中,而不是使用 Python 的字符串运算符。这避免了格式错误的查询或 sql 注入攻击的风险。参见例如this page。现在您的代码不会运行,因为它直接插入 dStart 和 dEnd 而没有任何引用,因此它们被解释为数学表达式 (2016 - 5 - 12 = 1999)。

还有一个次要问题是您的查询将排除 dateTime 值 on 结束日期,因为 endDate 将被视为具有 00:00:00 的时间值与dateTime 相比。如果您使用to_char() 或其他一些函数仅从dateTime 列中提取日期来进行比较,它将阻止您的查询使用索引,从而使其效率非常低。

以下是一些可能对您有用的修改代码:

def fn(dStart, dEnd):
    query = """ 
        SELECT "recordId" 
        FROM "Table" 
        WHERE "dateTime" >= %(start)s AND "dateTime" < %(end)s + interval '1 day'
    """
    query_params = {'start': dStart, 'end': dEnd}
    df1 = pd.read_sql_query(query1, con=engine, params=query_params)
    return df1

此代码依赖于一些假设(欢迎来到日期时间查询的精彩世界!):

  1. 您会将dStart 和dEnd 传递给fn(),而不仅仅是一个dateTime,
  2. dateTime 列是timestamp with timezone 类型(不是text),
  3. dateTime 列中的时区是正确的,并且
  4. dStart 和 dEnd 给出的日期在服务器的时区中,或者您已将 SET TIMEZONE ... 与您的 engine 对象一起使用来选择用于此会话的正确时区。

注意事项

不同的数据库引擎使用different placeholders 作为参数,因此您需要check your database driver's documentation 来决定使用哪些占位符。上面的代码应该适用于 postgresql。

使用上面的代码,dStart 和 dEnd 将作为字符串插入到查询中,并且 postgresql 在运行查询时会自动将它们转换为时间戳。这对于您提供的示例日期应该可以正常工作,但如果您需要更直接的控制,您有两个选择:

  1. 使用 Python 调用 fn() date 或 datetime 的值来获取 dStart 和 dEnd,上面的代码会将它们作为 postgresql 日期或时间戳插入到查询中;或
  2. 将dStart 和dEnd 字符串显式转换为postgresql 日期,方法是将%(start)s 和%(end)s 替换为to_date(%(start)s, 'YYYY-MM-DD')。

【讨论】:

  • 我已将其转换为时间戳。非常感谢 !!这已经奏效了
【解决方案2】:

我不熟悉 postgresql,但您可以将字符串转换为 struct_time 类,该类是 Python 中内置 time package 的一部分,并简单地在它们之间进行比较。

import time

time_data = ["2016-05-12T23:59:11+00:00", 
             "2016-05-13T11:00:11+00:00",  
             "2016-05-13T23:59:11+00:00", 
             "2016-05-15T10:10:11+00:00", 
             "2016-05-16T10:10:11+00:00", 
             "2016-05-17T10:10:11+00:00"]

def fn(t_init, t_fin, t_all):
    # Convert string inputs to struct_time using time.strptime()
    t_init, t_fin = [time.strptime(x, '%Y-%m-%d') for x in [t_init, t_fin]]
    t_all = [time.strptime(x, '%Y-%m-%dT%H:%M:%S+00:00') for x in time_all]
    out = []
    for jj in range(len(t_all)):
        if t_init < t_all[jj] < t_fin:
            out.append(jj)
    return out

out = fn('2016-05-12','2016-05-15', time_data)
print(out)
# [0, 1, 2]

time.strptime 例程使用格式说明符来指定字符串的哪些部分对应于不同的时间分量。

%Y  Year with century as a decimal number.
%m  Month as a decimal number [01,12].
%d  Day of the month as a decimal number [01,31].
%H  Hour (24-hour clock) as a decimal number [00,23].
%M  Minute as a decimal number [00,59].
%S  Second as a decimal number [00,61].
%z  Time zone offset from UTC.
%a  Locale's abbreviated weekday name.
%A  Locale's full weekday name.
%b  Locale's abbreviated month name.
%B  Locale's full month name.
%c  Locale's appropriate date and time representation.
%I  Hour (12-hour clock) as a decimal number [01,12].
%p  Locale's equivalent of either AM or PM.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-26
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多