#python #sql-server #pymssql
Вопрос:
Я пытаюсь выполнить несколько запросов в SQL Server, используя библиотеку pymssql.
Это мой код:
cur = conn.cursor()
cur.execute("DECLARE @begin_time datetime, @end_time datetime, @from_lsn binary(10), @to_lsn binary(10);
SET @begin_time = DATEADD(day, -1, GETDATE()) ;
SET @end_time = GETDATE();
SET @from_lsn = sys.fn_cdc_map_time_to_lsn('smallest greater than or equal', @begin_time);
SET @to_lsn = sys.fn_cdc_map_time_to_lsn('largest less than or equal', @end_time);
SELECT * FROM cdc.fn_cdc_get_net_changes_dbo_users(@from_lsn, @to_lsn, 'all');")
output = cur.fetchall()
print(output)
conn.close()
Код работает нормально и выдает результат, однако, когда я вычисляю дату с помощью библиотеки Python и передаю ее в код, я получаю сообщение об ошибке.
Пример кода
from datetime import datetime, timedelta
end_date = datetime.now()
start_date = datetime.now() timedelta(hours=-1)
cur = conn.cursor()
query = f"""DECLARE @begin_time datetime, @end_time datetime, @from_lsn binary(10), @to_lsn binary(10);
SET @begin_time = {start_date};
SET @end_time = {end_date};
SET @from_lsn = sys.fn_cdc_map_time_to_lsn('smallest greater than or equal', @begin_time);
SET @to_lsn = sys.fn_cdc_map_time_to_lsn('largest less than or equal', @end_time);
SELECT * FROM cdc.fn_cdc_get_all_changes_dbo_users (@from_lsn, @to_lsn, 'all');"""
print(query)
cur.execute(query)
output = cur.fetchall()
print(output)
conn.close()
Ошибка:
Ошибка программирования: (102, Неправильный синтаксис около «11».
Сообщение об ошибке DB-Lib 20018, степень серьезности 15:
Общая ошибка SQL Server: Проверка сообщений с сервера SQL
Я не уверен, что я здесь делаю не так. Был бы очень признателен, если бы кто-нибудь мог мне помочь и объяснить проблему.
Комментарии:
1. сообщение об ошибке показывает, что его синтаксис неверен
2. вот что я не могу понять, где я получаю неправильный синтаксис, так как тот же запрос отлично работает, когда я вычисляю время с помощью sql-запроса.
3. Возможно, это связано с тем, как формат данных передается в блок sql server. можете ли вы передать время начала в формате ГГГГ-ММ-ДД hh24:mi:ss
4. я пробовал это, но это не сработало 🙁
5. Когда вы печатаете запрос, ваши значения даты заключены в
'
символы? Вы можете попробовать использовать параметры привязки , чтобы убедиться, что они обрабатываются правильно.
Ответ №1:
Рассмотрите фактическую параметризацию SQL переменных времени, а не интерполяцию строк или объединение с F-строками, что, как правило, небезопасно или неэффективно для передачи значений с уровня приложения в серверную базу данных. Библиотека, pymssql
, поддерживает параметры. Python datetime.datetime
должен быть переведен на MSSQL DATETIME
.
# PREPARED STATEMENTS WITH %s PLACEHOLDERS
query = """DECLARE @begin_time datetime, @end_time datetime, @from_lsn binary(10), @to_lsn binary(10);
SET @begin_time = %s;
SET @end_time = %s;
SET @from_lsn = sys.fn_cdc_map_time_to_lsn('smallest greater than or equal', @begin_time);
SET @to_lsn = sys.fn_cdc_map_time_to_lsn('largest less than or equal', @end_time);
SELECT * FROM cdc.fn_cdc_get_all_changes_dbo_users (@from_lsn, @to_lsn, 'all');
"""
print(query)
# EXECUTE QUERY WITH BINDED PARAMS
cur.execute(query, [start_date, end_date])
На самом деле, вы можете сократить запрос, так как параметры не нуждаются в объявлении:
# PREPARED STATEMENTS WITH %s PLACEHOLDERS
query = """DECLARE @from_lsn binary(10), @to_lsn binary(10);
SET @from_lsn = sys.fn_cdc_map_time_to_lsn('smallest greater than or equal', %s);
SET @to_lsn = sys.fn_cdc_map_time_to_lsn('largest less than or equal', %s);
SELECT * FROM cdc.fn_cdc_get_all_changes_dbo_users (@from_lsn, @to_lsn, 'all');
"""
Кстати, обратите внимание pymmsql
, что библиотека больше не обслуживается. Рассмотрите pyodbc
возможность наиболее безопасного, обновленного DB-API для подключений Python-SQL Server. Но обратите внимание, что заполнителем параметров для pyodbc является qmarks ?
, а не %s
(в отличие от большинства API-интерфейсов Python DB).
Комментарии:
1. Рад помочь! Счастливого кодирования!