问题
I am trying to do something like this in Python,
SQLCommand = ("Delete From %s where [Date] >= %s and [Date] <= %s", (calendar_table_name, required_starting_date, required_ending_date))
cursor.execute(SQLCommand)
calendar_table_name
is a string
variable
required_starting_date
is a datetime
variable
required_ending_date
is a datetime
variable
Trying this gives me an error:
The first argument to execute must be a string or unicode query.
Tried this and it gives me the same error:
SQLCommand = ("Delete From " + calendar_table_name + " where [Date] >= %s and [Date] <= %s", ( required_starting_date, required_ending_date))
cursor.execute(SQLCommand)
Edit:
type(required_ending_date)
Out[103]: pandas._libs.tslibs.timestamps.Timestamp
type(required_starting_date)
Out[103]: pandas._libs.tslibs.timestamps.Timestamp
This works in SSMS for me,
delete from [table_test] where [Date] >= '2007-01-01' and [Date] <= '2021-01-01';
Update :- This is the code, that I am trying with
Delete_SQLCommand = f"Delete FROM [{calendar_table_name}] WHERE [Date]>=? And [Date]<=?"
params = (required_starting_date, required_ending_date)
required_starting_date & required_ending_date are of "TimeStamp" formats
calendar_tbl_connection = pyodbc.connect(driver=driver, server=required_server, database=database_name,
trusted_connection='yes')
calendar_tbl_cursor = calendar_tbl_connection.cursor()
calendar_tbl_cursor.execute(Delete_SQLCommand,params)
calendar_tbl_connection.commit
calendar_tbl_connection.close()
回答1:
pyodbc has no problem dealing with pandas' Timestamp
values as inputs to a proper parameterized query:
# test data
calendar_table_name = "#calendar_table"
crsr.execute(f"CREATE TABLE [{calendar_table_name}] ([Date] date)")
crsr.execute(f"INSERT INTO [{calendar_table_name}] VALUES ('2019-08-22'),('2019-08-24')")
df = pd.DataFrame(
[(datetime(2019, 8, 23, 0, 0), datetime(2019, 8, 25, 0, 0))],
columns=['required_starting_date', 'required_ending_date'])
required_starting_date = df.iloc[0][0]
required_ending_date = df.iloc[0][1]
print(type(required_starting_date)) # <class 'pandas._libs.tslibs.timestamps.Timestamp'>
# test
sql = f"DELETE FROM [{calendar_table_name}] WHERE [Date]>=? AND [Date]<=?"
params = (required_starting_date, required_ending_date)
crsr.execute(sql, params)
cnxn.commit()
#verify
rows = crsr.execute(f"SELECT * FROM [{calendar_table_name}]").fetchall()
print(rows) # [(datetime.date(2019, 8, 22), )]
回答2:
You don't say which library you are using for SQL access, but here is a safe example using psycopg
.
from psycopg2 import sql
cmd = sql.SQL("delete from {} where date >= %s and date <= %s")
table_name = sql.Identifier(calendar_table_name)
cur.execute(
cmd.format(table_name),
[required_starting_date, required_ending_date]
)
Note that this is not str.format
being called, but SQL.format
. The library ensures that calendar_table_name
is a proper column name, and SQL.format
ensures that it is correctly incorporated into your command template before in order to produce a valid parameterized query.
Failing proper library support, you would need to do some sort of dynamic query generation. It should be a restricted sort, though, the more restricted the better. The safest way would be to start with a lookup table of hard-coded queries:
queries = {
'name1': 'delete from name1 where ... ',
'name2': 'delete from name2 where ...',
}
This way, you can't construct a query for an arbitrary table name, only select a pre-constructed query.
The second would be to wrap the constructor in a function that checks for a valid table name first. For example,
def generate_query(table_name):
if table_name not in ['name1', 'name2', ...]:
raise ValueError("Invalid table name")
return "delete from {} where ...".format(table_name)
回答3:
You have 3 (at least) different problems with this code:
- You are using pandas Timestamp types instead of the expected python datetime types. Roganosh answer explains that
- You are mixing sql identifiers (table name) with sql values (date). You can only pass values as parameters to
cursor.execute
. see chepner's answer. - You are calling
cursor.execute
with incorrect arguments.
cursor.execute
expects two arguments. Since your SQLCommand
variable is a tuple, you can use *
to unpack the query string and the variables into two arguments when calling cursor.execute
.
SQLCommand = (
"DELETE FROM table_name WHERE date >= %s",
(datetime.date(2019, 08, 23),)
)
cursor.execute(*SQLCommand)
Note that you can't pass sql identfiers such as table names as parameters to the cursor.execute
method. The Python Database API Specification does not specify how to construct queries with dynamic identifiers (for example column or table names).
来源:https://stackoverflow.com/questions/57630431/python-passing-datetime-parameters-into-a-sql-command