【问题标题】:How do I return all values from a stored procedure?如何从存储过程中返回所有值?
【发布时间】:2009-05-29 19:45:29
【问题描述】:

请原谅我的幼稚,但我对将 Delphi 与数据库一起使用是新手(这对某些人来说可能看起来很奇怪)。

我已经使用 TADOConnection 建立了与我的数据库 (MSSQL) 的连接。我正在使用 TADStoredProc 来访问我的存储过程。

我的存储过程返回两列,一列包含服务器名称,第二列包含服务器上的用户。它通常返回大约 70 条记录...不是很多数据。

如何以编程方式枚举此存储过程?我可以在我的表单上删除一个 DBGrid 并将它附加到一个 TDataSource(然后附加到我的 ADOStoredProc),我可以验证数据是否被正确检索。

理想情况下,我想枚举返回的数据并将其移动到 TStringList 中。

目前,我正在使用以下代码枚举 ADOStoredProc,但它只返回 '@RETURN_VALUE':

ADOStoredProc1.Open;
ADOStoredProc1.ExecProc;
ADOStoredProc1.Parameters.Refresh;

for i := 0 to AdoStoredProc1.Parameters.Count - 1 do
begin
  Memo1.Lines.Add(AdoStoredProc1.Parameters.Items[i].Name);
  Memo1.Lines.Add(AdoStoredProc1.Parameters.Items[i].Value);
end;

【问题讨论】:

    标签: sql delphi stored-procedures


    【解决方案1】:

    调用 Open 以获取返回的数据集

    StoredProc.Open;
    while not StoredProc.EOF do
    begin
      Memo1.Lines.Add(StoredProc.FieldByName('xyz').Value);
      StoredProc.Next;
    end;
    

    【讨论】:

    • 不要在循环中使用 FieldByName!要么在设计时定义字段,要么在 Open 和 while 循环之间创建一个 Field 对象。
    • 为了清楚起见,我明确选择了那条路线。但是在帖子中,他指的是两列和 70 行,所以即使你这样做也不是很大的开销。但是,我从不使用在设计时定义的字段或按照您的建议创建字段对象。如果您想最小化开销,您可以按序号位置引用字段,这是我对已定义字段的偏好。
    【解决方案2】:

    使用 Open 从 StoredProc 中获取记录
    使用设计时字段,在循环之前使用 FieldByName 抓取的临时字段或 Fields[nn] 来获取值。

    procedure GetADOResults(AStoredProc: TADOStoredProc; AStrings: TStrings);
    var
      fldServer, fldUser: TField;
    begin
      AStoredProc.Open;
      fldServer := AStoredProc.FieldByName('ServerName');
      fldUser := AStoredProc.FieldByName('User');
      while not AStoredProc.EOF do
      begin
        AStrings.Add(Format('Server: %s - / User: %s',[fldServer.AsString, fldUser.AsString]));
        // or with FFields and Index (asumming ServerName is the 1st and User the 2nd) and no local vars
        AStrings.Add(Format('Server: %s - / User: %s',[AStoredProc.Fields[0].AsString, AStoredProc.Fields[1].AsString]));
        AStoredProc.Next;
      end;
    end;
    
    
    //use like
      GetADOResults(ADOStoredProc1, Memo1.Lines);
    

    注意:Fields[nn] 允许编写更少的代码,但要注意如果 StoredProc 更改了返回列的顺序。

    【讨论】:

      【解决方案3】:

      如果您的存储过程返回结果集(数据行),请不要使用 ExecProc。它旨在执行没有结果集的过程。改为使用 Open 或 Active,然后您可以像使用参数一样处理它们:

      ADOStoredProc.Open;
      
      for i := 0 to ADOStoredProc1.Parameters.Count - 1 do
      begin
        Memo1.Lines.Add(ADOStoredProc1.Parameters.Items[i].Name);
        Memo1.Lines.Add(ADOStoredProc1.Parameters.Items[i].Value);
      end;
      

      顺便说一句,调用 Open 然后 ExecProc 会导致问题; Open 返回一个结果集,然后 ExecProc 将其清除,因为您第二次运行该过程而没有预期的结果集。我也不认为您需要Parameters.Refresh,但我不能100% 确定。

      【讨论】:

      • 当代码循环通过Parameters集合时,SP返回结果集是否重要?即此代码不会返回与 OP 相同的结果吗? (免责声明:我不是 Delphi 程序员,所以也许我误解了这个问题......)
      • 当然很重要。 OP 使用 Open 获取结果集,然后使用 ExecSQL 将其丢弃,没有留下任何可循环的内容。删除 ExecSQL 并使用 Open(或 Active := True)会留下一个要迭代的结果集。 IOW,这与 OP 的结果不同。 :-)
      • 如果我没有误解,OP 想要的是记录而不是参数。他基本上想以编程方式获取 DBGrid 中返回的内容。
      • 阅读有关 AdoStoredProcedure 的 Delphi 文档。结果集在参数中返回。也测试了自己;你也可以这样做。 :-)
      • 啊,我明白了。代码看起来像是我应该能够阅读(如果不写)的东西,但我没想到参数中返回了结果集。 ;-) 谢谢,肯。
      【解决方案4】:

      看看这个(只是用谷歌搜索):

      [http://www.scip.be/index.php?Page=ArticlesDelphi12&Lang=EN#Procedure][1]
      

      基本上,SQL Server 存储过程总是返回一个返回值,但它也可以创建一个结果集,您需要像从常规 select 语句返回的数据集一样处理它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-07
        相关资源
        最近更新 更多