Pyodb c: ошибки вставки маринованных Python моделей на MS SQL сервер - PullRequest
2 голосов
/ 20 марта 2020

Некоторое время пытался устранить неисправность, но столкнулся с множеством проблем. Интересно, видел ли кто-нибудь это раньше?

Я пытаюсь pickle простой RandomForestClassifier (sklearn) в Python и использовать pyodbc, чтобы сохранить его в базе данных сервера MS SQL. В частности, я использую оператор UPDATE, потому что я обновляю ранее обученную модель.

Вот запрос, который я использую:

RF_serialized = pickle.dumps(RF)

RF_serialized_ins = str(RF_serialized)[1 : ] # doing this to cut off the leading 'b' from 
                                             # Python's byte data, per suggestions from other answers

q = "UPDATE table \
    SET serializedModel = CONVERT(VARBINARY(MAX), {}) \
    WHERE IDa = {} AND \
            IDb = {} AND \
            IDc = {}".format(RF_serialized_ins, "x", "y", "z")

Я продолжаю получать ошибка следующего неспецифического типа c:

pyodbc.ProgrammingError: ('42000', '[42000] [Microsoft][ODBC Driver 17 for SQL Server]Syntax error, permission violation, or other nonspecific error (0) (SQLExecDirectW)')

Кто-нибудь сталкивался с этим раньше? Я уверен, что идентификаторы и фильтры правильные, и т. Д. c. Тип данных целевого столбца VARBINARY(MAX). Одна идея: маринованный объект слишком большой? Размер объекта:

print("Type of python object:", type(RF_serialized))
print("The size of the pickled RF model is:", RF_serialized.__sizeof__())
Type of python object: <class 'bytes'>
The size of the pickled RF model is: 5487942

1 Ответ

1 голос
/ 21 марта 2020

Вот что в итоге сработало (спасибо @Gord Thompson за то, что меня направили в правильном направлении):

  1. Использование экранированной параметризации - согласно стандарту pyodbc, а не Python х .format(). В итоге мы изменили запрос на что-то вроде:
q = "UPDATE table \
    SET serializedModel = CONVERT(VARBINARY(MAX), ?) \
    WHERE IDa = CONVERT(uniqueidentifier, ?) AND \
            IDb = CONVERT(uniqueidentifier, ?) AND \
            IDc = CONVERT(uniqueidentifier, ?)"

args = (RF_serialized,
        "x",
        "y",
        "z")

cursor.execute(q, args)
cnxn.commit()
Использование CONVERT(uniqueidentifier, ?) вместо попытки ввода специальных символов для строк (например, \'), поскольку SQL Сервер обрабатывает идентификаторы GUID / уникальные идентификаторы как тип данных. У меня была пара дополнительных запросов зависание от запуска тестов / устранения неполадок, и я думаю, что дополнительный .execute() на одном из них - это полностью испортило запрос, который я на самом деле пытался исправить.
...