Delphi: "объект параметра неправильно определен. Была представлена непоследовательная или неполная информация."

Это функция, которая делает следующее:

  • создайте случайный токен с длиной 8
  • вставьте этот токен в базу данных
  • Если у пользователя уже есть токен, обновите его.

  • Если у пользователя нет токена, вставьте его.

procedure createToken(BenuNr: integer);
var
  AQ_Query:       TADOQuery;
  strToken:       string;
  intZaehler:     integer;
  const cCharSet: string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
begin
    //Random String as Token
    SetLength(strToken, 8);
  for intZaehler := 1 to 8 do
  begin
    strToken[intZaehler] := cCharSet[1+Random(Length(cCharSet))];
  end;
  //Inserts the Token into the Database
  with AQ_Query do
  begin
    try
      AQ_Query := TADOQuery.Create(nil);
      ConnectionString := strConnectionString;
      SQL.Text := 'if EXISTS(select * from TOKN where BENU_NR = :paramBenu_NR) begin update TOKN set TOKEN = :paramTOKEN where BENU_NR = :paramBenu_NR end else insert into TOKN (BENU_NR, TOKEN) values (:paramBENU_NR,:paramTOKEN)';
      Prepared := true;
      Parameters.ParamByName('paramBENU_NR').DataType := ftInteger;
      Parameters.ParamByName('paramTOKEN').DataType := ftString;
      Parameters.ParamByName('paramBENU_NR').Value := BenuNr;
      Parameters.ParamByName('paramTOKEN').Value := strToken;
      ExecSQL;    //<< Exception as stated in the title
    finally
      Free;
    end;
  end;
end;

выполнение этого вызывает у меня исключение, как указано в заголовке. Я вырежьте приведенный выше пример и вуаля: больше никаких исключений. К сожалению, я не понимаю, почему?

procedure createToken();
var
  AQ_Query:     TADOQuery;
  strToken:     string;
  intZaehler:      integer;
  const cCharSet:  string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
begin
    //Random String as Token
    SetLength(strToken, 8);
  for intZaehler := 1 to 8 do
  begin
    strToken[intZaehler] := cCharSet[1+Random(Length(cCharSet))];
  end;
  //Inserts the Token into the Database
  with AQ_Query do
  begin
    try
      AQ_Query := TADOQuery.Create(nil);
      ConnectionString := strConnectionString;
      SQL.Text := 'update TOKN set TOKEN = :paramTOKEN where BENU_NR = 1';
      Prepared := true;
      Parameters.ParamByName('paramTOKEN').DataType := ftString;
      Parameters.ParamByName('paramTOKEN').Value := strToken;
      ExecSQL;   //<< No more exception
    finally
      Free;
    end;
  end;
end;

Кажется, что на SQL разрешен только 1 параметр. Я использую Delphi 7 и MSSQL Server 2005

есть идеи, как исправить первый блок кода, чтобы он работал?

8 ответов


чтобы сделать эту работу вы должны использовать каждый параметр только один раз в условие SQL. Чтобы использовать один и тот же параметр более одного раза, просто объявите его с новым именем. Я не знаю, почему это так, но я знаю, что это может быть очень раздражает.


у меня была возможность попробовать это с компилятором :) я должен установить его дома когда-нибудь.

в то время как я все еще нахожу ваше использование с необычным, он, похоже, работает нормально.

Я видел ошибку, которую вы получаете в нескольких случаях:

  1. попытка выполнить более одного запроса против соединения сразу (из-за резьбы или таймера + processMessages)
  2. С TADOStoredProc, когда ProcedureName неверно
  3. иногда, если ADO не может проанализировать запрос - не может проверить это без вашей схемы БД.

обратите внимание, что в SQL Server Нет необходимости явно определять тип параметра. Они автоматически назначаются событием OnChanged, прикрепленным к объекту SQL TStringList.

в результате лучше всего либо назначить SQL.Свойство Text (как и вы), или при использовании .Добавить ('SELECT ...'), использовать SQL.BeginUpdate / SQL.Пара EndUpdate.

Оригинал ответ:

  with AQ_Query do
  begin
    try
      AQ_Query := TADOQuery.Create(nil);
      ConnectionString := strConnectionString;

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

aq_query должен быть создан перед оператором with:

  AQ_Query := TADOQuery.Create(nil);
  with AQ_Query do
  begin
    try
      ConnectionString := strConnectionString;

еще лучше не использовать С


пока эта ошибка является сложной задачей, вы можете диагностировать ее достаточно, чтобы увидеть, что ваш запрос является допустимым. Проблема в ваших параметрах. Лучший способ найти истинную проблему - это трассировка SQL Server Profiler вашей базы данных при поступлении запроса. Он покажет вам, как были интерпретированы параметры. Скопируйте этот запрос в текстовый редактор, чтобы узнать, в чем ваша проблема.

Если вы не можете использовать SQL Server Profiler, вы должны просто вывести значения "BenuNr" и " strToken" на экран или консоль, чтобы вы могли действительно видеть, что вы передаете в качестве параметров.


до сих пор я не исправил проблему.

но я думаю, что проблема лежит где-то внутри параметров и как к ним обращаются. Компилятор выбирает их по индексу, а не по имени, как я предполагал.

присмотревшись к компоненту TADOQuery в OI (особенно в разделе TParameters), вы можете увидеть, что индексы.

в конце концов это, вероятно, необходимо сначала добавить параметр, назначить ему имя, а затем вставить значение или что-то еще вроде этого.


выключите подготовку. Установите prepared=False для компонента ADO. Похоже, что сервер видит его до того, как оба параметра существуют, и готовит (компилирует) его. Когда вы выполняете его с двумя параметрами, список param не соответствует подготовленному оператору.


Оуч. Вы просто попали в то, что наш системный архитектор на работе называет "худшей ошибкой". Это довольно общая ошибка, и может означать все что угодно. Но я только когда-либо видел его на инструкциях INSERT, поэтому попробуйте посмотреть там. Это вызвано определением, что ADO каким-то образом не соответствует схеме базы данных.

попробуйте сократить запрос, чтобы сделать только вставку и использовать SQL profiler, включенный в SQL Management Studio, чтобы посмотреть, что делает ADO, когда он запускает его. Скорее всего, он запросит структуру вашей таблицы, сравните ее со структурой вашего оператора и в конечном итоге не понравится то, что он найдет, и никогда не отправит команду INSERT в базу данных.

убедитесь, что у вас есть правильные типы данных в полях, и что вы можете успешно выполнить вставку в таблицу, используя только эти два значения. Это может не сработать-это is худшая ошибка когда-либо, в конце концов, но это должно дать вам отправную точка.


вам не нужно указывать DataType. После успешного вызова Prepare; параметры должны быть настроены правильно, на основе определения таблицы сервера.

Я предполагаю, что, назначив DataType, параметр, вероятно, сброшен, и некоторая информация отсутствует, например,ParamType должно быть ptInput но сбрасывается до ptUnknown или что-то подобное.

Попробуйте удалить те строки, где вы установили тип данных, и посмотреть, поможет ли это.


для меня эта ошибка произошла без параметров, когда (в противном случае полностью допустимая) инструкция SQL содержала литеральное значение varchar с двоеточием (:) внутри цитируемого подтекста. Е. Г.

UPDATE ... SET myfield = 'foo " :bar "'

решением может быть переключение на параметры из уродливых встроенных литералов. Я еще не нашел другого подходящего обходного пути.