2014-10-20 3 views
1

DBExpress 및 Delphi XE를 사용하여 쿼리 벨로 우를 실행할 때 문제가 있습니다. 실행 된 쿼리에서 마지막 ID를 가져와야합니다.커서가 반환되지 않음 반환 값이있는 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에서 "open"이 그런 일을 할 수 없는지 궁금합니다. 어떤 방법을 사용해야합니까?

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; 

을 그리고 항상 null 값을 가지고, 어쩌면 다른 세션 때문에 (우리는 우리의 프로젝트에 대한 dbExpress를 사용해야합니다) 나는 이것을 시도했습니다. 나쁜 영어로 죄송합니다. 미리 도움을 청하십시오.

업데이트 : 우리가 @@ ID를 사용하는 경우 작동 :

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

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

을하지만, SQLServer에이 있다면 그 테이블에 트리거 (삽입에) 발사 있다는 이야기로 문제가있다는, 반환 값은 삽입 된 테이블의 마지막 ID. SQL 서버의 사용에

+1

저장 프로 시저를 사용하면 더 쉽게 사용할 수 있습니다. – whosrdaddy

답변

3

가장 우아한 방법은 하나 개의 ID 만 다중 삽입의 경우 모든 새로운 genered 하나를 반환 할뿐만 아니라 능력이되는 OUTPUT Clause 를 사용하는 수 있습니다. 당신이 당신의 테이블에 트리거를 가지고있는 경우

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

당신은 당신의 OUTPUT 또 다른 조언을 대신 하드 코딩 된 값의 매개 변수를 사용하는 것입니다

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

의 대상 테이블을 정의해야합니다.

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은 insert, update 등의 실행을 허용하지 않습니다. "cursor not returned query"오류가 발생합니다. 그리고 TSQLQuery.ExecSQL은 insert, update 등을 실행할 수 있지만 반환 값은 없습니다. ExecSQL과 Open을 사용하면 범위가 다르기 때문에 작동하지 않습니다. CMIIW – fmanda

+0

대단히 감사합니다. 'SET NOCOUNT ON'이 해결책입니다. 우리는 SQL Server 연결 등록 정보에서 'NO COUNT'를 checked = true로 설정했습니다. 그러나 그것은 효과가 없습니다. 그러나 우리가 당신의 솔루션을 사용할 때 : 기본 SQL 앞에 'SET NOCOUNT ON'을 추가 한 다음 Select scope_identity()를 선택하면이 메소드가 작동합니다. 그리고 우리는 당신의 충고를 시도 할 것입니다, 우리는 출력 Inserted.ID를 추가하고 클래스에서 생성하려고 노력할 것입니다. – fmanda

3

내가

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; 

그래서, 내가 소개이 사용 XE2와 SQL 서버를 수행하는 데 사용 : 문이 cursor not returned query 오류를 방지하려면 예상 된 결과를 제공하기 전에 TSQLQuery이 SET NOCOUNT ON를 추가로

두 번째 SQL 문의 as 키워드. 쿼리를 열 때 요청한 이름 'id'가있는 필드를 확인하십시오.

+0

감사합니다. 솔루션을 시도했지만 반환 값은 항상 0입니다. 아마도 ExecSQL와 Open이 같은 세션이지만 다른 범위이기 때문일 수 있습니다. 따라서 scope_identity()가 작동하지 않습니다[email protected]@ ID를 사용하면 범위를 읽을 수 있기 때문에 결과를 얻을 수 있지만 다른 테이블에 삽입하는 트리거가 테이블에있는 경우 잘못된 결과가 발생합니다. – fmanda