Ошибка типа: Connection.execute() получил неожиданный аргумент ключевого слова при выполнении хранимой процедуры

Я пытаюсь вставить данные в таблицу базы данных MSSQL, выполняя хранимую процедуру с помощью скрипта Python.

Вот моя хранимая процедура -

  SET ANSI_NULLS ON GO
  SET QUOTED_IDENTIFIER ON GO
  CREATE PROCEDURE [dbo].[Sp_Test] 
( 
   @ProcessId INT
  ,@CreatedByUserName VARCHAR(12)
  ,@CreatedByMachineName VARCHAR(12)
  --,@CreatedTime DATETIME
  ,@NumberOfDataRows INT  
  ,@DataSource VARCHAR(300)
  --,@RefId VARCHAR(8)
  ,@Postpone DATETIME2
  ,@Deadline DATETIME2
  ,@NewBatchId INT OUT 
) 
  AS  
  BEGIN    
  INSERT INTO Test(ProcessId, CreatedByUserName,
  CreatedByMachineName, CreatedTime, Postpone, Deadline,
  NumberOfDataRows, DataSource, RefId)   
  VALUES(
   @ProcessId,
   @CreatedByUserName, 
   @CreatedByMachineName, 
   GETDATE(), 
   NULL, 
   NULL,
   @NumberOfDataRows, 
   @DataSource, 
   CONVERT(VARCHAR(9),
   CRYPT_GEN_RANDOM(4), 2)
)
  SET @NewBatchId = SCOPE_IDENTITY();
  RETURN 0; 
END 
GO

Вот мой фрагмент кода Python.

with engine.connect() as conn:
                conn.execute(text("CALL Sp_Test(:ProcessId, :CreatedByUserName, :CreatedByMachineName, :NumberOfDataRows, :DataSource)"), ProcessId=process_code, CreatedByUserName=username,CreatedByMachineName=hostname,NumberOfDataRows=row_count,DataSource='Shared')

Но когда я пытаюсь запустить свой скрипт, он выдает следующую ошибку.

Ошибка типа: Connection.execute() получил неожиданный аргумент ключевого слова «ProcessId».

Я также пытался передать значения как словарь. Но ошибка та же.

params = {'ProcessId': process_code,'CreatedByUserName': username,'CreatedByMachineName': hostname,'NumberOfDataRows': row_count,'DataSource': 'Shared'} 
with engine.connect() as conn: 
conn.execute(text("CALL Sp_Test(:ProcessId, :CreatedByUserName, :CreatedByMachineName, :NumberOfDataRows, :DataSource)"),**params)

Благодарю, если кто-нибудь может помочь мне разобраться в этом?

@snakecharmerb я удалил **. Но теперь я получаю ошибку программирования pyodbc как 'sqlalchemy.exc.ProgrammingError: (pyodbc.ProgrammingError) ('42000', "[42000] [Microsoft][ODBC Driver 17 для SQL Server][SQL Server]Неправильный синтаксис рядом с '@P1 '. (102) (SQLExecDirectW); [42000] [Microsoft][Драйвер ODBC 17 для SQL Server][SQL Server]Не удалось подготовить операторы (8180)")'.

Punya Munasinghe 24.05.2024 11:28

Возможно, лучше попробовать вызвать процедуру следующим образом docs.sqlalchemy.org/en/20/core/… - но я не использую SQL-Server, поэтому, боюсь, не могу предоставить никаких подробных предложений. .

snakecharmerb 24.05.2024 11:55

Для pyodbc вам нужно будет использовать анонимный блок кода, как описано здесь.

Gord Thompson 24.05.2024 13:31

Также обратите внимание, что T-SQL (диалект MS SQL Server) не использует CALL, он использует EXECUTE (часто сокращается до EXEC).

Gord Thompson 24.05.2024 13:52

Вы заметили, что ни один из параметров хранимой процедуры не имеет значений по умолчанию? Это означает, что все они должны быть указаны при вызове хранимой процедуры. то есть: если вы попытаетесь EXEC dbo.sp_Test @ProcessId=1,@CreatedByUserName='username',@CreatedByMachine‌​Name='machinename',@‌​NumberOfDataRows=1,@‌​DataSource='shared'; из SSMS или DBeaver, вы получите сообщение об ошибке. Процедура или функция «Sp_Test» ожидает параметр «@Postpone», который не был предоставлен.

AlwaysLearning 24.05.2024 14:55
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
5
179
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как упоминалось в комментарии к вопросу, документация pyodbc для вызова хранимых процедур, которые возвращают ВЫХОДНЫЕ переменные и/или ВОЗВРАЩАЕМЫЕ значения, находится здесь. Однако в вашем случае вам не нужно прибегать к необработанному курсору DBAPI, поскольку ваш SP не возвращает наборы результатов, поэтому вам не нужно вызывать метод .nextset() pyodbc. Вы можете использовать SQLAlchemy напрямую, как в следующем упрощенном примере.

Данный

CREATE TABLE [dbo].[Test](
    [BatchId] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [ProcessId] [int] NOT NULL
)

CREATE PROCEDURE [dbo].[my_test_sp]
@ProcessId int, @NewBatchId int OUT
AS
BEGIN
    SET NOCOUNT ON;
    INSERT INTO Test (ProcessId) VALUES (@ProcessId);
    SET @NewBatchId = SCOPE_IDENTITY();
    RETURN 0;
END

Мы сможем

from sqlalchemy import create_engine, text

engine = create_engine("mssql+pyodbc://scott:tiger^5HHH@mssql_199")

with engine.begin() as conn:
    sql = """\
        SET NOCOUNT ON;
        DECLARE @new_id int, @rtn int;
        EXEC @rtn = dbo.my_test_sp @ProcessId = :process_id, @NewBatchId = @new_id OUTPUT;
        SELECT @new_id AS new_batch_id, @rtn AS return_value;
        """
    result = conn.execute(text(sql), dict(process_id=123)).mappings().one()
    print(result)  # {'new_batch_id': 2, 'return_value': 0}

Спасибо. Благодаря этому мой код запустился без ошибок, и похоже, что процедура вызывается, но данные не отображаются в таблице. Тем не менее, я получаю правильный результат NewBatchId для каждой вставки. (тот же запрос работает нормально при прямом вызове). Этот ответ работает для меня, но тогда я не могу так элегантно использовать переменные параметры. Есть идеи, что я делаю неправильно?

Punya Munasinghe 26.05.2024 23:20

Вы можете установить engine.echo = True непосредственно перед блоком with и проверить вывод журнала, чтобы увидеть, происходит ли COMMIT.

Gord Thompson 27.05.2024 00:09

Спасибо за engine.echo = True. Каким-то образом тот же код начал работать сегодня.

Punya Munasinghe 27.05.2024 22:10

Другие вопросы по теме