Параметры запроса Python — Pandas — SQL — Не удается отфильтровать данные без двойных кавычек

#python #sql #pandas

#python #sql #pandas

Вопрос:

Я получаю некоторые данные из базы данных, используя операции запроса pandas read sql:

 import pandas as pd
date_filter = '2020-01-01'
df = pd.read_sql_query(f"SELECT * FROM table WHERE date_id>= {date_filter }", my_connection)
  

Если я запущу этот код, фильтр не будет применен, и он выведет все данные.
Однако, если я заключу переменную в двойные кавычки:

 df = pd.read_sql_query(f"SELECT * FROM table WHERE date_id>= '{date_filter }'", my_connection)
  

Это делает фильтр правильно.

Почему? Я допускаю какую-либо ошибку?

Комментарии:

1. Это имеет смысл, потому что в SQL вы бы фильтровали '2020-01-01' .

2. Нет, вы не совершаете ошибку, SQL не любит необработанные строки даты без кавычек, потому что нет простого разделителя, чтобы распознать, что это один токен

Ответ №1:

Вам нужно обернуть апострофы вокруг переменной, потому что без переменной вы получите запрос типа

 SELECT * FROM table WHERE date_id>= 2020-09-08
  

это недопустимый SQL. Вам нужно обернуть апострофами значение, чтобы иметь допустимый синтаксис:

 SELECT * FROM table WHERE date_id>= '2020-09-08'
  

Именно по этой причине вам нужно обернуть апострофы вокруг вашего шаблона.

Ответ №2:

Без кавычек, я бы предположил, что анализатор SQL может выполнять вычитание частей года / месяца / дня в вашей переменной:

 SELECT * FROM table WHERE date_id >= 2020-01-01

SELECT * FROM table WHERE date_id >= 2018
  

И поскольку большинство дат в базах данных отформатированы в секундах от эпохи ( 1970-01-01 00:00:00 ). Удобочитаемое преобразование 2018 занимает несколько минут от epoch, в частности Thursday, January 1, 1970 12:33:38 AM . Следовательно, почему возвращаются почти все ваши данные.

 SELECT * FROM table WHERE date_id >= '1970-01-01 12:33:38'
  

Как вы узнали, цитирование буквальных значений даты работает, но еще лучшим решением является параметризация, которая поддерживается в pandas.read_sql . Для ясности, F-строки — это не параметризация, а просто более новая версия интерполяции строк. Также обратите внимание, что заполнитель параметра отличается в зависимости от DB-API, и символ не должен заключаться в кавычки или объединяться в каких-либо арифметических или других операциях.

 # cxOracle
df = pd.read_sql_query("SELECT * FROM table WHERE date_id >=  :1", 
                       my_connection, params=[date_filter])

# psycopg2, pymysql, pymssql
df = pd.read_sql_query("SELECT * FROM table WHERE date_id >=  %s", 
                       my_connection, params=[date_filter])

# pyodbc, sqlite3, ibm_db, jaydebeapi
df = pd.read_sql_query("SELECT * FROM table WHERE date_id >=  ?", 
                       my_connection, params=[date_filter])