Sql server TADOStoredProc和SQL Server存储过程,参数为默认值

Sql server TADOStoredProc和SQL Server存储过程,参数为默认值,sql-server,delphi,delphi-7,ado,Sql Server,Delphi,Delphi 7,Ado,我正在使用Delphi7和SQLServer2008。我创建了一个虚拟表和虚拟存储过程,如下所示 CREATE TABLE [dbo].[Persons] ( [P_ID] [int] IDENTITY(1,1) NOT NULL, [LastName] [varchar](255) NOT NULL ) CREATE PROCEDURE [dbo].[p_dummy_proc] @p_id int, @p_name VARCHAR(10) = 'dummy'

我正在使用Delphi7和SQLServer2008。我创建了一个虚拟表和虚拟存储过程,如下所示

CREATE TABLE [dbo].[Persons]
(
    [P_ID] [int] IDENTITY(1,1) NOT NULL,
    [LastName] [varchar](255) NOT NULL
)

CREATE PROCEDURE [dbo].[p_dummy_proc]
    @p_id int,
    @p_name VARCHAR(10) = 'dummy' -- donot pass anything from delphi and it should take 'dummy'
AS
BEGIN 
    IF (@p_name is null)
        RAISERROR 123456 'why are you null'
    ELSE  
        INSERT INTO dbo.persons(LastName) 
        VALUES(@p_name)
END
我从Delphi调用上述过程如下:

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    ADOStoredProc1.Parameters.ParamByName('@p_id').Value := 10;
    ADOStoredProc1.ExecProc; // error why are you null
  except
   on E: EDatabaseError do
     ShowMessage(e.Message);
  end;
end;
在Delphi代码中,我没有传递第二个参数,我希望SQLServer应该采用它的默认值

当我执行存储过程时,我得到一个错误。当我没有从Delphi传递任何信息时,为什么SQL Server不接受默认值

如果我将参数值设置为“dummy”,它将按预期工作。 TL;DR-要使用设置的默认SP参数值:

ADOStoredProc1.Parameters.ParamByName('@p_name').ParameterObject.Value := Unassigned
在Delphi代码中,我没有传递第二个参数,而是 希望SQL Server采用其默认值

是的,你是。您在设计时使用的是一个已经存在的参数,因此此参数将显式地作为NULL发送到SQL Server。您可以通过检查SQL探查器来验证这一点

如果必须使用设计时参数,则无论何时使用默认参数,都可以在运行时将其删除,或者以其他方式创建/分配它。e、 g您可以为此制定一个通用方法:

var
  Param: TParameter;
  ParamName: WideString;
  ParamValue: Variant;
  UseDefaultParameter: Boolean;
begin
  ParamName := '@p_name';
  Param := ADOStoredProc1.Parameters.FindParam(ParamName);
  UseDefaultParameter := True; // or False to assign a value

  if UseDefaultParameter then
  begin
    if Assigned(Param) then
      ADOStoredProc1.Parameters.Delete(Param.Index);
  end
  else
  begin
    ParamValue := 'boo!';
    if Assigned(Param) then
      Param.Value := ParamValue
    else
      ADOStoredProc1.Parameters.CreateParameter(ParamName, ftString, pdInput, 10, ParamValue);
  end;
end;
否则,不要使用设计时参数,并根据需要在运行时创建参数。IMO的一个更好的方法是使用本地TADOStoredProc,在运行时创建它,分配参数,执行它,然后销毁它

就我个人而言,我在运行时创建TADOStoredProc并调用方法,该方法将从SQL Server查询和创建参数。然后,我只需将这些值分配给所需的参数。即使有一个额外的SQL Server行程,在向SP添加新参数时进行维护也非常方便。 如果未设置参数值,ADO将启动exec命令,使用默认关键字设置参数。i、 e

exec p_dummy_proc @p_id=1, @p_name=default
在进一步挖掘之后,我注意到问题实际上存在于TParameter.SetValue setter中。无法清除参数值:

procedure TParameter.SetValue(const Value: Variant);
begin
  if VarIsEmpty(Value) or VarIsNull(Value) then <--
    NewValue := Null
  else
  begin
    ...
  end;  
  ParameterObject.Value := NewValue;
end;

你到底犯了什么错误?@kirchner:用错误更新了问题。错误是为什么为null。@nil::我没有看到参数的任何绑定属性。好的,所以SQL Server接收到显式null。为了应用默认值,您不能为参数传递任何内容,甚至不能为NULL。当您在代码中没有为参数提供值时,可能基础结构正在传递空默认值?您可以尝试从参数列表中删除@p_名称吗?只有在设计时添加参数,我才能重现您描述的行为。如果我在设计时不这样做并调用参数。在指定参数值之前在执行时刷新,它工作正常-无错误,并且调用分析器显示默认关键字。您上次的编辑很整洁。ParameterObject.Value:=Unassigned基本上等同于Parameter.Value=在研究这个问题时,我在.NET中没有找到任何内容。但是我在Delphi中没有成功,因为我用TParameter进行了尝试。@nil,我在调用Parameters.Refresh并检查参数(包括ParameterObject)后意识到了这一点。我知道必须有一些东西可以清除参数值。真的很像未赋值的值,以前从未使用过,但从现在起我会这样做
if UseDefaultParameter then 
  SP.Parameters.ParamByName('@p_name').ParameterObject.Value := Unassigned
else
  SP.Parameters.ParamByName('@p_name').Value := 'boo!'