2014-10-20 123 views
1

使用DBExpress和Delphi XE執行query bellow時遇到問題。我需要從執行的查詢中獲取最後一個身份標識:如果執行帶返回值的SQL語句,則不返回查詢遊標

function TServerDBUtils.ExecuteQueryWithIdentity(ASQLConn: TSQLConnection): Integer; 
var 
    newSQLQuery: TSQLQuery; 
begin 
    Result := -1; 
    newSQLQuery := TSQLQuery.Create(nil); 
    try 
    with newSQLQuery do 
    begin 
     SQLConnection := ASQLConn; 

     SQL.Clear; 
     SQL.Add('Insert into SampleTable(uomname) values(' + Quotedstr('bag') +')'; 

     SQL.Add('Select Scope_Identity()'); 
     Open; 
     Result:= Fields[0].AsInteger;  
    end; 
    finally 
    FreeAndNil(newSQLQuery); 
    end; 
end; 

我收到錯誤「遊標未返回查詢」。我之前使用過相同的方法,使用FireDac & Delphi XE5並沒有出錯。不,我想知道是否「開放」不允許在DBExpress中做這樣的事情。我應該使用什麼方法? (我們在我們的項目中使用的dbExpress) 我已經試過這樣:

function TServerDBUtils.ExecuteQueryWithIdentity(ASQLConn: TSQLConnection): Integer; 
var 
    newSQLQuery: TSQLQuery; 
begin 
    Result := -1; 
    newSQLQuery := TSQLQuery.Create(nil); 
    try 
    with newSQLQuery do 
    begin 
     SQLConnection := ASQLConn; 

     SQL.Clear; 
     SQL.Add('Insert into SampleTable(uomname) values(' + Quotedstr('bag') +')'; 
     ExecSQL; 

     SQL.Clear; 
     SQL.Add('Select Scope_Identity()'); 
     Open; 
     Result:= Fields[0].AsInteger;  
    end; 
    finally 
    FreeAndNil(newSQLQuery); 
    end; 
end; 

而且總是得到空值,也許是因爲不同的會話。 對不起,我英語不好,並提前感謝任何幫助。

更新: 如果我們使用@@標識它的工作原理:

SQL.Add('Insert into SampleTable(uomname) values(' + Quotedstr('bag') +')'; 
ExecSQL; 

SQL.Clear; 
SQL.Add('Select @@Identity'); 
Open; 
Result:= Fields[0].AsInteger; 

但是,有問題,SQLServer的說,如果有被解僱(插入)上表中的觸發器,返回值是觸發器插入的表的最後一個ID。

+1

使用存儲過程,會讓你的生活更輕鬆。 – whosrdaddy 2014-10-20 12:13:08

回答

3

SQL-Server上最優雅的方式可能是使用的 OUTPUT Clause 這不僅能夠返回一個ID,但所有新genered一個在多插入的情況下。

INSERT into aTable (aField) 
OUTPUT Inserted.ID 
Values ('SomeValue') 

如果你有你的桌子上觸發你必須定義一個目標表爲輸出

DECLARE @tmp table (ID int) 
INSERT into aTable (aField) 
OUTPUT Inserted.ID into @tmp 
Values ('SomeValue') 
Select * from @tmp 

另一個建議是使用參數,而不是硬編碼值。

隨着TSQLQuery加入SET NOCOUNT ON前聲明將阻止cursor not returned query錯誤的實現預期的結果:

begin 
    SQLQuery1.SQL.text :='SET NOCOUNT ON' 
       +#13#10'DECLARE @tmp table (ID int)' 
       +#13#10'INSERT into aTable (aField)' 
       +#13#10'OUTPUT Inserted.ID into @tmp' 
       +#13#10'Values (:P)' 
       +#13#10'Select * from @tmp'; 
    SQLQuery1.Params.ParamByName('P').Value := 'SomeText'; 
    SQLQuery1.Open; 
    Showmessage(SQLQuery1.Fields[0].asString); 
end; 
+0

謝謝,仍然是TSQLQuery它自身的問題。我們必須使用TSQLQuery.Open來從查詢中檢索任何返回。但TSQLQuery.Open不允許我們執行插入,更新等。我們會收到錯誤「遊標未返回查詢」。而TSQLQuery.ExecSQL可以執行插入,更新等,但沒有任何返回值。如果我們使用ExecSQL然後打開,由於範圍不同,它不起作用。 CMIIW – fmanda 2014-10-20 08:45:45

+0

非常感謝,'SET NOCOUNT ON'是解決方案。我們已經在我們的SQL Server連接屬性中嘗試過,並且使'NO COUNT'checked = true。但它不起作用。但是,當我們使用您的解決方案時:在主SQL之前添加'SET NOCOUNT ON',然後選擇select scope_identity(),此方法有效。我們也會嘗試你的建議,我們會嘗試添加輸出Inserted.ID並在我們的類中生成。 – fmanda 2014-10-21 02:20:03

3

我用它來做到這一點使用XE2和SQL Server

with newSQLQuery do 
try  
    SQLConnection := ASQLConn; 
    SQL.Clear; 
    SQL.Add('Insert into SampleTable(uomname) values(' + Quotedstr('bag') +')'); 
    ExecSQL; 

    SQL.Clear; 
    SQL.Add('Select Scope_Identity() as id'); 
    Open; 

    if not Eof then 
    Result := FieldByName('id').asInteger; 
finally 
    FreeAndNil(newSQLQuery); 
end; 

所以,我介紹第二個SQL語句中的as關鍵字。當我打開查詢時,只需檢查被請求的名稱爲「id」的字段。

+0

謝謝,我已經嘗試了您的解決方案,但返回值始終爲0.也許是因爲ExecSQL和Open是同一會話但範圍不同。所以scope_identity()不起作用。如果我們使用@@標識,我們會得到結果,因爲它會讀取任何範圍,但是如果在表中插入其他表中的觸發器,我們將得到錯誤的結果。 – fmanda 2014-10-21 02:10:00