Q&A

  • 조인된 SQL 업데이트(마이다스+오라클805+델5)
Delphi 5 Contact 중의 "5부 분산 환경 솔루션/38장 마이다스의 활용 (1439 페이지)"



내용을 적용하던중에 의문사항이 있어서 씁니다.



같은 내용을 저자인 박준후님에게 메일을 보냈으나 답변이 늦어지는군요... --;



클라이언트에는 TSocketConnection 1개와 TClientDataSet 1개를,



서버의 리모트데이타모듈에는 TQuery 1개와 TDataSetProvier1개,



그리고 TUpdateSQL 2개(Master용과 Detail용)를 올려놨습니다.



근데, 문제는 마스터는 저장이 되는데 디테일 저장시에



OnReconcilError 에서 찍어보니 디테일 테이블의 컬럼에서 Constraint 가 발생네요...



혹시 같은 작업을 해 보신분이나 제가 한 작업에 관심있으신분은



아래 소스를 보시고 조언 바랍니다.



의도는 서버의 리모트데이탑모듈이 Create 될때, UpdateSQL 의 SQL 구문을



자동생성하여 조인된 테이블을 업데이트하는 겁니다.



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++





Client 모듈에서 데이타를 추가한후 ApplyUpdate 를 날리면



Master 는 저장이 되지만 다음과 같은 에러가 발생합니다.



Field value required.

ORA-01400: cannot insert NULL into ("ICM"."AGRMAST"."AMSUCODE")



마스터 테이블에는 값이 제대로 들어 갔는데 디테일 테이블에 값이 할당 되지 않는것 같군요



왜 마스터에 저장된 키값으로 디테일까지 저장이 안되는지 알고 싶습니다.



물론



다음은 제가 구현한 부분입니다. 보시고 잘못된 곳이 있다면 알려 주십시오



0. 환경



툴 : 델5

DB : Oracle 8.0.5

DB 서버 : Linux

App 서버 : NT40

Client : Win98



1. 클라이언트



(1) 콤포넌트



sccnAgree : TSocketConnection

cdstMaster : TClientDataSet



(2) 코딩



< SQL 구문 >



SELECT AGRMAST.*, AGRDETAIL.*,

ITEM.INAME,

STITEM.STNAME,

STITEM.STUNIT

FROM AGRMAST, AGRDETAIL, STITEM, ITEM

WHERE AGRMAST.SITE_MEMBER_MID = AGRDETAIL.AGRMAST_SITE_MEMBER_MID AND

AGRMAST.SITE_SCODE = AGRDETAIL.AGRMAST_SITE_SCODE AND

AGRMAST.AMSUCODE = AGRDETAIL.AGRMAST_AMSUCODE AND

AGRDETAIL.AGRMAST_SITE_MEMBER_MID = :P_MID AND

AGRDETAIL.AGRMAST_SITE_SCODE = :P_SCODE AND

AGRDETAIL.AGRMAST_AMSUCODE = :P_SUCODE AND

AGRDETAIL.STITEM_STCODE = STITEM.STCODE AND

AGRDETAIL.ADICODE = ITEM.ICODE

ORDER BY AGRDETAIL.ADSEQ, STITEM.STNAME, STITEM.STUNIT, AGRDETAIL.ADICODE, ITEM.INAME





2. 서버



(1) 콤포넌트



qryAgree : TQuery

usqlMaster : TUpdateSQL

usqlDetail : TUpdateSQL



(2) 코딩



procedure TrdmIAgree.dstpIAgreeBeforeUpdateRecord(Sender: TObject; // 책에 있는 루틴

SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind;

var Applied: Boolean);

begin

usqlMaster.DataSet := qryIAgree;

usqlDetail.DataSet := qryIAgree;



pSetUsqlParams(usqlMaster.Query[UpdateKind], DeltaDS);



usqlMaster.ExecSQL(UpdateKind);



pSetUsqlParams(usqlDetail.Query[UpdateKind], DeltaDS);



usqlDetail.ExecSQL(UpdateKind);



Applied := True;

end;





procedure TrdmIAgree.pSetUSQLParams(qrySet : TQuery; cdstSet : TClientDataSet); // 책에 있는 루틴

var

liI : Integer;

lbOld : Boolean;

loParam : TParam;

lsParamName : String;

loField : TField;

lvValue : Variant;

begin

with qrySet do

begin

for liI := 0 to Params.Count-1 do

begin

loParam := Params[liI];

lsParamName := loParam.Name;

lbOld := CompareText(Copy(lsParamName, 1, 4), 'OLD_') = 0;



if lbOld then

System.Delete(lsParamName, 1, 4);



loField := cdstSet.FindField(lsParamName);



if not Assigned(loField) then

Continue;



if lbOld then

loParam.AssignFieldValue(loField, loField.OldValue)

else

begin

lvValue := loField.NewValue;



if VarIsEmpty(lvValue) then

lvValue := loField.OldValue;



loParam.AssignFieldValue(loField, lvValue);

end;

end;

end;

end;





procedure TrdmIAgree.pSetUsqlSQL(usqlSet : TUpdateSQL; lsTableName : String; lasFields, lasKeyFields : array of String);

// 넘겨진 UpdateSQL 의 ModifySQL, InsertSQL, DeleteSQL 을 생성합니다.

// 디자인시에는 TQuery 의 필드 및 TUpdateSQL 에 관한 내용이 전혀 없습니다.

var

liI : Integer;

lsModifySQL, lsInsertSQL, lsDeleteSQL : String;

begin

with usqlSet do

begin

lsModifySQL := 'UPDATE ' + lsTableName + #13 +

'SET' + #13;



for liI := Low(lasFields) to High(lasFields)-1 do

begin

lsModifySQL := lsModifySQL + lasFields[liI] + ' = :' + lasFields[liI] + ',' + #13;

end;



lsModifySQL := lsModifySQL + lasFields[High(lasFields)] + ' = :' + lasFields[High(lasFields)] + #13;



lsModifySQL := lsModifySQL + 'WHERE' + #13;



for liI := Low(lasKeyFields) to High(lasKeyFields)-1 do

begin

lsModifySQL := lsModifySQL + lasKeyFields[liI] + ' = :OLD_' + lasKeyFields[liI] + ' AND' + #13;

end;



lsModifySQL := lsModifySQL + lasKeyFields[High(lasKeyFields)] + ' = :OLD_' + lasKeyFields[High(lasKeyFields)] + #13;





lsInsertSQL := 'INSERT INTO ' + lsTableName + #13 +

'(';



for liI := Low(lasFields) to High(lasFields)-1 do

begin

lsInsertSQL := lsInsertSQL + lasFields[liI] + ',' + #13;

end;



lsInsertSQL := lsInsertSQL + lasFields[High(lasFields)] + ')' + #13 +

'VALUES' + #13 +

'(';



for liI := Low(lasFields) to High(lasFields)-1 do

begin

lsInsertSQL := lsInsertSQL + ':' + lasFields[liI] + ',' + #13;

end;



lsInsertSQL := lsInsertSQL + ':' + lasFields[High(lasFields)] + ')';





lsDeleteSQL := 'DELETE FROM ' + lsTableName + #13 +

'WHERE' + #13;



for liI := Low(lasKeyFields) to High(lasKeyFields)-1 do

begin

lsDeleteSQL := lsDeleteSQL + lasKeyFields[liI] + ' = :OLD_' + lasKeyFields[liI] + ' AND' + #13;

end;



lsDeleteSQL := lsDeleteSQL + lasKeyFields[High(lasKeyFields)] + ' = :OLD_' + lasKeyFields[High(lasKeyFields)];





ModifySQL.Clear();

ModifySQL.Add(lsModifySQL);



InsertSQL.Clear();

InsertSQL.Add(lsInsertSQL);



DeleteSQL.Clear();

DeleteSQL.Add(lsDeleteSQL);

end;

end;







procedure TrdmIAgree.RemoteDataModuleCreate(Sender: TObject); // 리모트 데이타 모듈이 생성될때 TUpdateSQL 의 SQL 구문 생성

begin

pSetUsqlSQL(usqlMaster,

'AGRMAST',

[ 'SITE_MEMBER_MID',

'SITE_SCODE',

'AMSUCODE',

'AMKUMK'],

[ 'SITE_MEMBER_MID',

'SITE_SCODE',

'AMSUCODE']);



pSetUsqlSQL(usqlDetail,

'AGRDETAIL',

[ 'AGRMAST_SITE_MEMBER_MID',

'AGRMAST_SITE_SCODE',

'AGRMAST_AMSUCODE',

'ADSEQ',

'STITEM_STCODE',

'ADICODE',

'ADSNO',

'ADQTY',

'ADUPR',

'ADKUMK'],

[

'AGRMAST_SITE_MEMBER_MID',

'AGRMAST_SITE_SCODE',

'AGRMAST_AMSUCODE']);

end;





다음은 위의 모듈을 클라이언트에서 실행하여 시뮬해본 결과 생성된 SQL 구문입니다.



{



===============================마스터



UPDATE AGRMAST

SET

SITE_MEMBER_MID = :SITE_MEMBER_MID,

SITE_SCODE = :SITE_SCODE,

AMSUCODE = :AMSUCODE,

AMKUMK = :AMKUMK

WHERE

SITE_MEMBER_MID = :OLD_SITE_MEMBER_MID AND

SITE_SCODE = :OLD_SITE_SCODE AND

AMSUCODE = :OLD_AMSUCODE



INSERT INTO AGRMAST

(SITE_MEMBER_MID,

SITE_SCODE,

AMSUCODE,

AMKUMK)

VALUES

(:SITE_MEMBER_MID,

:SITE_SCODE,

:AMSUCODE,

:AMKUMK)



DELETE FROM AGRMAST

WHERE

SITE_MEMBER_MID = :OLD_SITE_MEMBER_MID AND

SITE_SCODE = :OLD_SITE_SCODE AND

AMSUCODE = :OLD_AMSUCODE



===============================================디테일



UPDATE AGRDETAIL

SET

AGRMAST_SITE_MEMBER_MID = :AGRMAST_SITE_MEMBER_MID,

AGRMAST_SITE_SCODE = :AGRMAST_SITE_SCODE,

AGRMAST_AMSUCODE = :AGRMAST_AMSUCODE,

ADSEQ = :ADSEQ,

STITEM_STCODE = :STITEM_STCODE,

ADICODE = :ADICODE,

ADSNO = :ADSNO,

ADQTY = :ADQTY,

ADUPR = :ADUPR,

ADKUMK = :ADKUMK

WHERE

AGRMAST_SITE_MEMBER_MID = :OLD_AGRMAST_SITE_MEMBER_MID AND

AGRMAST_SITE_SCODE = :OLD_AGRMAST_SITE_SCODE AND

AGRMAST_AMSUCODE = :OLD_AGRMAST_AMSUCODE



INSERT INTO AGRDETAIL

(AGRMAST_SITE_MEMBER_MID,

AGRMAST_SITE_SCODE,

AGRMAST_AMSUCODE,

ADSEQ,

STITEM_STCODE,

ADICODE,

ADSNO,

ADQTY,

ADUPR,

ADKUMK)

VALUES

(:AGRMAST_SITE_MEMBER_MID,

:AGRMAST_SITE_SCODE,

:AGRMAST_AMSUCODE,

:ADSEQ,

:STITEM_STCODE,

:ADICODE,

:ADSNO,

:ADQTY,

:ADUPR,

:ADKUMK)



DELETE FROM AGRDETAIL

WHERE

AGRMAST_SITE_MEMBER_MID = :OLD_AGRMAST_SITE_MEMBER_MID AND

AGRMAST_SITE_SCODE = :OLD_AGRMAST_SITE_SCODE AND

AGRMAST_AMSUCODE = :OLD_AGRMAST_AMSUCODE



}

0  COMMENTS