Передача значения NULL в параметризованный запрос сервера SQL delphi

Я пытаюсь передать нулевое значение параметру TSQLDataset. Запрос имеет вид:

Query_text:='MERGE INTO [Table] 
             USING (VALUES (:A,:B)) AS Source (Source_A, Source_B)
             ....
             WHEN MATCHED THEN 
             UPDATE SET A = :A
             WHEN NOT MATCHED THEN
             INSERT(A, B) VALUES (:A,:B);

SQL_dataset.CommandType:=ctQuery; 
SQL_dataset.CommandText:=Query_text;

SQL_dataset.ParamByName('A').AsString:='A';  
SQL_dataset.ParamByName('B').AsString:={ COULD BE NULL, OR A STRING };    

SQL_dataset.ExecSQL;

Параметр B может принимать значение NULL, но также является внешним ключом. Если пользователь что-то вводит в это поле, то B необходимо сверить со значениями в другой таблице. Если он пуст, я хочу, чтобы его игнорировали. Я передавал '', но это, очевидно, приводит к ошибке нарушения FK.

Я старался:

SQL_dataset.ParamByName('B').Value:=Null;

... но затем я получаю сообщение об ошибке «драйвер dbexpress не поддерживает тип данных tdbxtypes.unknown».

Я также пробовал:

SQL_dataset.ParamByName('B').DataType:=ftVariant;
SQL_dataset.ParamByName('B').Value:=Null;

.. но затем получил ошибку «драйвер dbexpress не поддерживает тип данных tdbxtypes.variant».

Не уверен, что я делаю неправильно, любая помощь будет оценена по достоинству. В настоящее время я составляю список параметров в зависимости от того, заполнена строка или нет, и это работает хорошо; это просто немного неуклюже (в моем фактическом запросе), так как нужно проверить довольно много параметров.

Я использую Delphi XE4 и SQL Server 2012.

Обновление:

Спасибо за всю помощь, ваши предложения были правильными с самого начала, это было что-то еще, что вызвало эту ошибку «драйвер dbexpress». Я создавал «гибкий» список параметров, чтобы обойти свою проблему, и это вызвало исключение:

Parameter_string:='';

If B<>'' then Parameter_string:='B = :B,'

Query_text:='MERGE ...'
            '...'
            'UPDATE SET A = :A, '+Parameter_string+' C = :C' ....

... идея заключается в том, что если B пусто, параметр не будет «перечислен» в запросе.

Это не работает, или моя реализация не работает (не знаю почему, я явно где-то пропустил шаг).

Во всяком случае, рабочий код:

Query_text:='MERGE ...'
            '...'
            'UPDATE SET A = :A, B = :B, C = :C' ....

SQL_dataset.CommandType:=ctQuery; 
SQL_dataset.CommandText:=Query_text;

If B<>'' then
begin
  SQL_dataset.ParamByName('B').AsString:='B';
end
else
begin
  SQL_dataset.ParamByName('B').DataType:=ftString;
  SQL_dataset.ParamByName('B').Value:=Null;
end;

person Alex    schedule 11.06.2013    source источник


Ответы (3)


что о:

SQL_dataset.ParamByName('B').Clear;

person pf1957    schedule 11.06.2013
comment
Я читал это предложение в другом месте, но я получаю, что драйвер dbExpress не поддерживает тип данных TDBXTypes.UNKNOWN. Сообщение об ошибке поставщика: ошибка, когда я пытаюсь это сделать. Я делаю что-то еще не так? - person Alex; 12.06.2013
comment
Странно... в настоящее время я перехожу с FIB+ на FireDAC, и я протестировал его на обоих подключениях, и можно использовать либо Clear, либо Value := null присваивание. И я ожидаю, что это работает с каждым набором данных. По крайней мере, я никогда не сталкивался с этой проблемой, но я никогда не использовал dbExpress. - person pf1957; 12.06.2013

Если я правильно помню, эквивалентом db-null в Delphi является Variants.Null

person souplex    schedule 11.06.2013

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

var
 Query_text:String;
begin
  Query_text:='Declare @A varchar(100) ' // or e.g. integer
       +#13#10'Declare @B varchar(100)'  
       +#13#10'Select @A=:A'
       +#13#10'Select @B=:B'
       +#13#10'Update Adressen Set Vorname=@A,Strasse=@B where Name=@B';
  SQL_dataset.CommandType := ctQuery;
  SQL_dataset.CommandText := Query_text;
  SQL_dataset.Params.ParseSQL(SQL_dataset.CommandText,true);
  Showmessage(IntToStr(SQL_dataset.Params.Count));
  SQL_dataset.ParamByName('B').DataType := ftString;
  SQL_dataset.ParamByName('B').Value := 'MyText';
  SQL_dataset.ParamByName('A').DataType := ftString;  // or e.g. ftInteger
  SQL_dataset.ParamByName('A').Value := NULL;
  SQL_dataset.ExecSQL;
end;
person bummi    schedule 11.06.2013
comment
Спасибо, я попробовал это, получаю ту же ошибку, что и указанная выше в комментарии к @ pf1957. Может быть, у меня есть что-то еще, что вызывает эту ошибку? - person Alex; 12.06.2013