[英]Filtering SQL query based on parameters with more than one value
我正在嘗試構建一個需要用兩個參數(2列)過濾的SQL,第二列需要匹配多個值。
下面給出的是我到目前為止構建的SQL(感謝Martijn Pieters的幫助)
import psycopg2
import pandas as pd
import datetime
# Connecting to db
con = psycopg2.connect(db_details)
cur = con.cursor()
cur.execute("select * from sales limit 10")
rows = cur.fetchall()
params = {'earliest': datetime.datetime.today() - datetime.timedelta(days=7),
'store_name': 'store_1', 'store_2'}
df = pd.read_sql("""
select store_name,count(*) from sales
where created_at >= %(earliest)s
and store_name = %(store_name)s""",
params=params, con=con)
上面的SQL有一個date參數,該參數在where子句中使用,我又添加了一個參數,即store_name ,其中行與兩個值之一匹配。
想知道如何將這個附加參數添加到現有查詢中。
我試圖創建一個參數(類似於日期過濾器)並將其傳遞給現有查詢,但是當我給它兩個值時會出現語法錯誤:
'store_name': 'store_1', 'store_2'}
^
SyntaxError: invalid syntax
指向params
字段。
您有兩個問題:
您使用了無效的Python語法; 字典中的逗號分隔鍵值對,因此'store_2'
字符串將是另一個鍵值對,但缺少: value
部分。 如果要使用多個字符串定義一個值,則必須在其中使用元組或列表,如果您明確使用(...)
或[...]
將該語法與key: value, key: value
分開key: value, key: value
表示法:
params = { 'earliest': datetime.datetime.today() - datetime.timedelta(days=7), 'store_name': ('store_1', 'store_2'), # tuple with two values }
一般來說,SQL參數只能使用單個值 。 只能給store_name
參數一個值,而不是一個值序列。 這是因為SQL參數是SQL查詢和該查詢中要使用的動態值之間的橋梁,而這些參數旨在充當每個單獨的動態值的占位符。
也就是說, psycopg2
庫專門支持元組 ,但這是大多數Python數據庫庫的例外。
接下來,如果要過濾匹配'store_1'
或'store_2'
,則正確的SQL語法將是使用兩個store_name = ...
測試,在它們之間使用OR
並將其括在括號中(以使該部分與date
分開)測試,並使用AND
將其連接到商店名稱測試), 或使用store_name IN ('store_1', 'store_2')
。 IN
測試將列名與(...)
括號中列出的多個值進行比較。
假設您在此處使用psycopg2
,則可以不用引用元組值的store_name
鍵,但是您確實需要對查詢使用IN
:
params = {
'earliest': datetime.datetime.today() - datetime.timedelta(days=7),
'store_name': ('store_1', 'store_2')
}
df = pd.read_sql("""
SELECT store_name, count(*) FROM sales
WHERE created_at >= %(earliest)s
AND store_name IN %(store_name)s""",
params=params, con=con)
單獨說明: pd.read_sql()
函數[明確指出在使用DBAPI連接時僅支持sqlite](如果為DBAPI2對象,則僅支持sqlite3):
如果是DBAPI2對象,則僅支持sqlite3。
您正在使用這樣的對象; 大多數Python數據庫適配器都是DBAPI2庫; DBAPI2是此類庫的Python標准 。
您實際上應該改用SQLAlchemy連接字符串 。 您的代碼恰好工作,因為你永遠不會嘗試任何數據寫回到數據庫和psycopg連接和光標對象是與sqlite3的庫版本大體兼容,但你可能會遇到的道路問題。
我不明白為什么這行不通:
params = {'earliest': datetime.datetime.today() - datetime.timedelta(days=7),
'store_name': '<put what you want here>'}
df = pd.read_sql("""
select store_name,count(*) from sales
where created_at >= %(earliest)s
and store_name = %(store_name)s""",
params=params, con=con)
因為要兩個商店,所以有點復雜。
這應該工作:
params = {'earliest': datetime.datetime.today() - datetime.timedelta(days=7),
'store_names': ','.join(('store_1', 'store_2'))}
df = pd.read_sql("""
select store_name,count(*) from sales
where created_at >= %(earliest)s
and store_name in (%(store_names)s)""",
params=params, con=con)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.