2008-10-31 58 views
10

我的一些MS SQL存儲過程使用'print'命令產生消息。在我使用TADOConnection連接到MS SQL的Delphi 2007應用程序中,如何查看這些「打印」命令的輸出?使用Delphi中的ADOConnection查看「print」語句的輸出

關鍵需求: 1)我無法多次運行查詢;它可能會更新的東西。 2)即使數據集被返回,我也需要看到「打印」結果。

回答

9

這是一個有趣的...
從ADOConnection的OnInfoMessage事件工作,但惡魔是在細節!

要點:
使用的CursorLocation =的clUseServer而不是默認的clUseClient。
在您的ADOStoredProc中使用Open而不是ExecProc。
使用NextRecordset從當前一個獲得以下,但一定要檢查你有一個打開。
在存儲過程中使用SET NOCOUNT = ON。

SQL方面:存儲過程

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[FG_TEST]') AND type in (N'P', N'PC')) 
    DROP PROCEDURE [dbo].[FG_TEST] 
GO 
-- ============================================= 
-- Author:  François 
-- Description: test multi ADO with info 
-- ============================================= 
CREATE PROCEDURE FG_TEST 
AS 
BEGIN 
    -- SET NOCOUNT ON absolutely NEEDED 
    SET NOCOUNT ON; 

    PRINT '*** start ***' 

    SELECT 'one' as Set1Field1 

    PRINT '*** done once ***' 

    SELECT 'two' as Set2Field2 

    PRINT '*** done again ***' 

    SELECT 'three' as Set3Field3 

    PRINT '***finish ***' 
END 
GO 

德爾福方:
創建一個新的VCL窗體應用程序。
在您的表單中放入備忘錄和按鈕。

複製下面的文本,改變目錄和數據源並粘貼到您的表單

object ADOConnection1: TADOConnection 
    ConnectionString = 
    'Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security In' + 
    'fo=False;Initial Catalog=xxxYOURxxxDBxxx;Data Source=xxxYOURxxxSERVERxxx' 
    CursorLocation = clUseServer 
    LoginPrompt = False 
    Provider = 'SQLOLEDB.1' 
    OnInfoMessage = ADOConnection1InfoMessage 
    Left = 24 
    Top = 216 
end 
object ADOStoredProc1: TADOStoredProc 
    Connection = ADOConnection1 
    CursorLocation = clUseServer 
    ProcedureName = 'FG_TEST;1' 
    Parameters = <> 
    Left = 24 
    Top = 264 
end 

在的ADOConnection的OnInfoMessage把

Memo1.Lines.Add(Error.Description); 

對於ButtonClick,粘貼此代碼

procedure TForm1.Button1Click(Sender: TObject); 
const 
    adStateOpen = $00000001; // or defined in ADOInt 
var 
    I: Integer; 
    ARecordSet: _Recordset; 
begin 
    Memo1.Lines.Add('=========================='); 

    ADOStoredProc1.Open; // not ExecProc !!!!! 

    ARecordSet := ADOStoredProc1.Recordset; 
    while Assigned(ARecordSet) do 
    begin 
    // do whatever with current RecordSet 
    while not ADOStoredProc1.Eof do 
    begin 
     Memo1.Lines.Add(ADOStoredProc1.Fields[0].FieldName + ': ' + ADOStoredProc1.Fields[0].Value); 
     ADOStoredProc1.Next; 
    end; 
    // switch to subsequent RecordSet if any 
    ARecordSet := ADOStoredProc1.NextRecordset(I); 
    if Assigned(ARecordSet) and ((ARecordSet.State and adStateOpen) <> 0) then 
     ADOStoredProc1.Recordset := ARecordSet 
    else 
     Break; 
    end; 

    ADOStoredProc1.Close; 
end; 
+0

這絕對會讓我走上正軌:爲了獲得靈活性,我使用了TADOCommand而不是TADOStoredProc,它仍然有效。 SET NOCOUNT ON也似乎是可選的:如果您沒有它,它只會打印額外的消息。並且clUseServer使記錄集在TDBGrid中不可用:( – apenwarr 2008-11-03 17:58:02

1

我不認爲這是可能的。 您可以使用臨時表來轉儲打印語句並將其與結果一起返回。

3

在.net的連接類中有一個名爲InfoMessage的事件。在此事件的處理程序中,您可以從事件參數中檢索InfoMessage(打印語句)。

我相信德爾福有一個類似的事件,稱爲「OnInfoMessage」,可以幫助你。

+1

This is close!它工作,如果我設置command.ExecuteOptions = [eoExecuteNoRecords]。但是這阻止了我獲取任何數據集。嗯...... – apenwarr 2008-10-31 20:13:08

0

對Francois的代碼進行了一些增強(使用DXE2進行測試)以配合用於多個打印語句以及來自可變數量選擇的結果。這些變化很微妙。

procedure TForm1.ADOConnection1InfoMessage(Connection: TADOConnection; 
    const Error: Error; var EventStatus: TEventStatus); 
var 
    i: integer; 
begin 
    // show ALL print statements 
    for i := 0 to AdoConnection1.Errors.Count - 1 do 
    begin 
    // was: cxMemo1.Lines.Add(Error.Description); 
    cxMemo1.Lines.Add(
     ADOConnection1.Errors.Item[i].Description); 
    end; 
end; 

procedure TForm1.cxButton1Click(Sender: TObject); 
const 
    adStateOpen = $00000001; // or uses ADOInt 
var 
    records: Integer; 
    ARecordSet: _RecordSet; 
begin 
    cxMemo1.Lines.Add('=========================='); 

    ADOStoredProc1.Open; 

    try 
    ARecordSet := ADOStoredProc1.RecordSet; // initial fetch 
    while Assigned(ARecordSet) do 
    begin 
     // assign the recordset to a DataSets recordset to traverse 
     AdoDataSet1.Recordset := ARecordSet; 
     // do whatever with current ARecordSet 
     while not ADODataSet1.eof do 
     begin 
     cxMemo1.Lines.Add(ADODataSet1.Fields[0].FieldName + 
      ': ' + ADODataSet1.Fields[0].Value); 
     AdoDataSet1.Next; 
     end; 
     // fetch next recordset if there is one 
     ARecordSet := ADOStoredProc1.NextRecordSet(records); 
     if Assigned(ARecordSet) and ((ARecordSet.State and adStateOpen) <> 0) then 
     ADOStoredProc1.Recordset := ARecordSet 
     else 
     Break; 
    end; 
    finally 
    ADOStoredProc1.Close; 
    end; 

end;