отображается «по умолчанию», значит, в процедуре или функции указано слишком много аргументов;

Общая цель

Перепишите часть веб-сайта, доступную для давних клиентов, которая по-прежнему зависит от выполнения SQL-запроса формата и в настоящее время работает должным образом:

SQLQuery = "exec spNewPayments " & "162611"
  Set rsPmts = objConnection.Execute(SQLQuery)

Где 162611 — целое число. Затем цель состоит в том, чтобы параметризовать запрос с помощью объекта command и добавить параметры, используя метод .Parameters.Append .CreateParameter.

Кроме того, вторичная цель состоит в том, чтобы в конечном итоге добавить дополнительные параметры, чтобы ограничить область запроса, но я даже не зашел так далеко в этом посте.

Проблема

При выполнении запроса с использованием objConnection.Execute хранимая процедура выполняется, как и ожидалось, с одним параметром, целым числом (см. выше). При выполнении запроса с помощью команды recordsource.Open я получаю сообщение:

  spNewPayments has too many arguments specified
  Code: 80040E14

Хранимая процедура создается с использованием:

USE [maindb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER OFF
GO

CREATE PROCEDURE [dbo].[spNewPayments] @claim_id int = NULL AS
select *
FROM dbo.objectTest co
WHERE co.foreign_id = @claim_id;

GO

VBScript, который я сейчас использую в качестве теста:

Dim strCnxn 
strCnxn = "DSN=myDSN"
Dim objConnection
Set objConnection = CreateObject("ADODB.Connection")  
objConnection.Mode = acModeRead
objConnection.Open strCnxn

Dim cmd
Set cmd = CreateObject("ADODB.Command")
Dim rsPmts 
Set rsPmts = CreateObject("ADODB.Recordset")
With cmd
.ActiveConnection = objConnection

.CommandType = 4
.CommandText = "spNewPayments"

.Parameters.Refresh

.Parameters.Append .CreateParameter("@claim_id", 3, , , 162611)

End With

rsPmts.Open cmd
rsPmts.Close 

Set rsPmts = Nothing
 Set objConnection = Nothing
 Set cmd = Nothing

Как уже упоминалось, когда я запускаю это, я получаю: «Процедура или функция spNewPayments имеет слишком много аргументов». Это происходит в строке rsPmts.Open cmd

Я отслеживаю с помощью Profiler в SQL Server MS, чтобы увидеть, как сервер отвечает, и я вижу:

declare @p1 int
set @p1=180150003
declare @p3 int
set @p3=8
declare @p4 int
set @p4=1
declare @p5 int
set @p5=2
exec sp_ddopen @p1 output,N'sp_sproc_columns',@p3 output,@p4 output,@p5 output,N'spNewPayments',NULL,NULL,NULL
select @p1, @p3, @p4, @p5
go
exec sp_cursorfetch 180150003,2,1,1
go
exec sp_cursorfetch 180150003,2,1,1
go
exec sp_cursorfetch 180150003,2,1,1
go
exec sp_cursorclose 180150003
go
exec spNewPayments default,162611
go

Ага! Похоже, он передает два параметра, первый параметр по умолчанию. Хм? Что это такое? Как он туда попадает?

Очевидно, это вызвано слишком большим количеством параметров, но я не думаю, что мой код добавляет два параметра, а только один.

Эта ошибка также появляется, когда люди непреднамеренно попадают в цикл, но я еще даже не добрался до своего цикла. Я планирую просмотреть recordsource позже.


person CarloTex    schedule 24.09.2018    source источник


Ответы (2)


.Parameter.Refresh() заставляет ADO запрашивать параметры у SQL Server, что является накладными расходами, которые вы можете увидеть в предоставленной вами трассировке SQL Profiler. Вызов этого метода автоматически заполняет коллекцию .Parameters, но не рекомендуется для производства из-за запроса сервера на заполнение коллекции при каждом выполнении.

Эти строки в трассировке связаны с вызовом .Parameters.Refresh;

-- Declaration and setting of temporary varibles
declare @p1 int
set @p1=180150003
declare @p3 int
set @p3=8
declare @p4 int
set @p4=1
declare @p5 int
set @p5=2
/*
Execution of sp_sproc_columns to get the expected parameters from the
spNewPayments stored procedure (see https://stackoverflow.com/q/7903268/692942).
*/
exec sp_ddopen @p1 output,N'sp_sproc_columns',@p3 output,@p4 output,@p5 output,N'spNewPayments',NULL,NULL,NULL
select @p1, @p3, @p4, @p5
go
-- Use cursor to loop through results.
exec sp_cursorfetch 180150003,2,1,1
go
exec sp_cursorfetch 180150003,2,1,1
go
exec sp_cursorfetch 180150003,2,1,1
go
-- Close the cursor.
exec sp_cursorclose 180150003
go

Причина ошибки в том, что вы затем вручную добавляете параметр, используя методы .Parameters.Append() и CreateParameter(). Это сработало бы нормально и было бы моим рекомендуемым подходом, если бы вы не вызывали сначала Refresh(), фактически удваивая параметр @claim_id в коллекции Parameters, в результате чего он имел Too many arguments.

Итак, исправление в вашем примере кода заключается в удалении;

.Parameters.Refresh

Полезные ссылки

person user692942    schedule 25.09.2018

Есть две вещи, на которые я обычно смотрю, которые должны это исправить.

Во-первых, устанавливается свойство CommandType объекта ADODB.Command в adCmdStoredProc следующим образом:

cmd.CommandType = adCmdStoredProc 

Но вы, возможно, уже сделали это в этой строке:

.CommandType = 4

Я просто не уверен по памяти, какое значение имеет константа adCmdStoredProc.

Другой вариант — поместить заполнитель прямо в текст команды:

.CommandText = "spNewPayments @claim_id"

Это лучше всего подходит для adCmdText CommandType и обычно не требуется или не помогает, если CommandType было установлено на adCmdStoredProc, так что это та или иная ситуация. Я видел, как это делается эффективно в обоих направлениях.

Оглядываясь назад, вы можете захотеть .Parameters.Clear, а не .Parameters.Refresh, но, поскольку вы только что создали объект, вам это тоже не нужно, и прошло очень много времени с тех пор, как я использовал ADO старой школы.

person Joel Coehoorn    schedule 24.09.2018
comment
Когда я использовал cmd.CommandType = adCmdStoredProc, я получаю сообщение об ошибке ADODB.Command (13, 2) : Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another. Я думаю, что это указывало на то, что константа недоступна, поэтому я прочитал здесь docs.microsoft.com/en-us/sql/ado/reference/ado-api/ и присвоил ему значение 4 вместо. .Parameters.Clear указывает, что объект не поддерживает это должным образом или метод: 'Parameters.Clear' - person CarloTex; 25.09.2018
comment
Когда я пробую заполнитель и CommandType = 1, я получаю [Microsoft][ODBC SQL Server Driver][SQL Server]Must declare the scalar variable "@claim_id", который, кажется, возвращается из самого SQL Server. Интересно, что я заставил его работать, вставив cmd.Parameters.Delete 1 перед моей строкой cmd.Parameters.Append. Он возвращает нужный набор записей и все такое. Это как если бы к объекту прикреплялся секретный скрытый параметр по умолчанию при его создании, и я должен сначала удалить его, прежде чем добавлять к нему. - person CarloTex; 25.09.2018
comment
Да, CommandType=1 должен работать, когда вы также меняете текст команды, чтобы включить заполнитель, например: .CommandText = "spNewPayments @claim_id". Не уверен, откуда взялся дополнительный параметр. Может быть полезно или поучительно распечатать несколько отладочных сообщений с именем и типом параметра. - person Joel Coehoorn; 25.09.2018
comment
@CarloTex, попробуйте удалить .Parameters.Refresh из исходного кода. Это заполняет коллекцию параметров из метаданных, тогда как вы добавляете параметр вручную. - person Dan Guzman; 25.09.2018
comment
Не используйте Refresh, так как это приведет к тому, что сервер заполнит коллекцию Parameters (как видно из трассировки SQL Profiler в вопросе). Ошибка возникает из-за того, что вы Append обращаетесь к набору параметров после его обновления. Если вы просто хотите установить значения для отправки, вы должны использовать .Parameters(“@claim_id”).Value = 162611. На данный момент он снова добавляется, что вызывает ошибку too many arguments specified. В приведенном выше коде удаление .Parameters.Refresh исправит это. - person user692942; 25.09.2018
comment
В CommandType нет ничего плохого, за исключением того, что мы рекомендуем использовать именованные константы из ADO, так что это должно быть adCmdStoredProc. Вы используете только заполнители в adCmdText, потому что он предназначен для динамического выполнения SQL. - person user692942; 25.09.2018
comment
Кроме того, единственный заполнитель, который работает с adCmdText, — это ?, вы не можете использовать @claim_id. - person user692942; 25.09.2018