TADOStoredProc 和 SQL 服务器存储过程,参数为默认值
TADOStoredProc and SQL Server stored procedure with parameter as default value
我正在使用 Delphi 7 和 SQL Server 2008。我创建了一个虚拟 table 和虚拟存储过程,如下所示。
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 代码中,我没有传递第二个参数,我希望 SQL 服务器应该采用它的默认值。
当我执行存储过程时,出现错误。当我没有从 Delphi 传递任何内容时,为什么 SQL 服务器不采用默认值?
如果我将参数值设置为 'dummy',它会按预期工作。
TL;DR - 要使用默认 SP 参数值集:
ADOStoredProc1.Parameters.ParamByName('@p_name').ParameterObject.Value := Unassigned
In the Delphi code, I am not passing second parameter and I am
expecting that SQL Server should take it's default value.
是的,你是。您在设计时使用了一个已经存在的参数,因此该参数被显式地作为 NULL 发送到 SQL 服务器。您可以通过检查 SQL 分析器来验证这一点。
如果您必须使用设计时间参数,您可以在运行时间内删除它,只要默认参数是指要使用或 create/assign 否则。例如(你可以为此制定一个通用方法):
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
并调用 Parameters.Refresh()
方法,该方法将从 SQL 服务器查询(和创建)参数。然后我只需将值分配给我需要的参数。虽然多了一趟SQL服务器,但是在给SP增加新参数的时候维护起来还是很方便的
如果未设置参数值,ADO 将启动一个 exec
命令,使用 default
关键字设置参数。即
exec p_dummy_proc @p_id=1, @p_name=default
进一步挖掘后,我注意到问题实际上在TParameter.SetValue
setter。没办法"clear"参数值:
procedure TParameter.SetValue(const Value: Variant);
begin
if VarIsEmpty(Value) or VarIsNull(Value) then <--
NewValue := Null
else
begin
...
end;
ParameterObject.Value := NewValue;
end;
您可以看到,如果您将 Value
设置为 NULL
或 Unassigned
,ParameterObject.Value
将设置为 NULL
(但永远不会默认值)。
所以如果需要清除某个参数,使用默认值,需要直接将TParameter.ParameterObject.Value
设置为Unassigned
:
if UseDefaultParameter then
SP.Parameters.ParamByName('@p_name').ParameterObject.Value := Unassigned
else
SP.Parameters.ParamByName('@p_name').Value := 'boo!'
我正在使用 Delphi 7 和 SQL Server 2008。我创建了一个虚拟 table 和虚拟存储过程,如下所示。
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 代码中,我没有传递第二个参数,我希望 SQL 服务器应该采用它的默认值。
当我执行存储过程时,出现错误。当我没有从 Delphi 传递任何内容时,为什么 SQL 服务器不采用默认值?
如果我将参数值设置为 'dummy',它会按预期工作。
TL;DR - 要使用默认 SP 参数值集:
ADOStoredProc1.Parameters.ParamByName('@p_name').ParameterObject.Value := Unassigned
In the Delphi code, I am not passing second parameter and I am expecting that SQL Server should take it's default value.
是的,你是。您在设计时使用了一个已经存在的参数,因此该参数被显式地作为 NULL 发送到 SQL 服务器。您可以通过检查 SQL 分析器来验证这一点。
如果您必须使用设计时间参数,您可以在运行时间内删除它,只要默认参数是指要使用或 create/assign 否则。例如(你可以为此制定一个通用方法):
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
并调用 Parameters.Refresh()
方法,该方法将从 SQL 服务器查询(和创建)参数。然后我只需将值分配给我需要的参数。虽然多了一趟SQL服务器,但是在给SP增加新参数的时候维护起来还是很方便的
如果未设置参数值,ADO 将启动一个 exec
命令,使用 default
关键字设置参数。即
exec p_dummy_proc @p_id=1, @p_name=default
进一步挖掘后,我注意到问题实际上在TParameter.SetValue
setter。没办法"clear"参数值:
procedure TParameter.SetValue(const Value: Variant);
begin
if VarIsEmpty(Value) or VarIsNull(Value) then <--
NewValue := Null
else
begin
...
end;
ParameterObject.Value := NewValue;
end;
您可以看到,如果您将 Value
设置为 NULL
或 Unassigned
,ParameterObject.Value
将设置为 NULL
(但永远不会默认值)。
所以如果需要清除某个参数,使用默认值,需要直接将TParameter.ParameterObject.Value
设置为Unassigned
:
if UseDefaultParameter then
SP.Parameters.ParamByName('@p_name').ParameterObject.Value := Unassigned
else
SP.Parameters.ParamByName('@p_name').Value := 'boo!'