26
Geschäftslogik in der Datenbank Architektur und Objektorientierte PL/SQL-Programmierung Andriy Terletskyy Lead Database Architect Hamburg, 17.06.2010

Geschäftslogik in der Datenbank - berenberg.de · 2 12.06.2012 Geschäftslogik in der Datenbank Geschäftslogik Geschäftslogik (engl.Business Logic, auch Anwendungslogik) ist ein

Embed Size (px)

Citation preview

Geschäftslogik in der Datenbank Architektur und Objektorientierte

PL/SQL-Programmierung

Andriy Terletskyy

Lead Database Architect Hamburg, 17.06.2010

2 12.06.2012 Geschäftslogik in der Datenbank

Geschäftslogik

Geschäftslogik (engl. Business Logic, auch Anwendungslogik) ist

ein abstrakter Begriff in der Softwaretechnik, der eine Abgrenzung der

durch die Aufgabenstellung selbst motivierten Logik eines

Softwaresystems von der technischen Implementierung zum Ziel hat.

Allerdings ist der Begriff unscharf, da eine klare Trennung oft nicht

möglich ist.

Daten-Import

Datenbank

Java

ASP.NET

FAT-Client

Cobol

• Oracle EE ist mehr als eine

Datenbank (Speicherort)

• SQL und PL/SQL Engine

• DBMS-Packages

• Object Types

• Type Mapping (Java&.NET)

• JPublisher, SQLData,

STRUCT, ODP.NET

• Mehrfache BL-Umsetzung

• Datenbank Abhängigkeit

• Datenverarbeitungs- und

Datenerfassungslogik

3 12.06.2012 Geschäftslogik in der Datenbank

Datenbanken Architektur

Bestandstamm

GattungStamm

KundenStamm

Transaktionen

Ausführung

Order

Log

Log

Log

Log

MaklerFIX

E-Börsen SWIFT

Handelssystem

Back-Office

Data-Warehouse

Loglog

Log

Bestandstamm

GattungStamm

KundenStamm

(Data-HUBs)

Abrechnung

Abrechnung

Transaktionen

Ausführung

Order

Bestandstamm

GattungStamm

KundenStamm

Log

Buchung

Portfolio

Bestandstamm

GattungStamm

KundenStamm

Buchung

Transaktionen

Aufrührung

OrderBuchung

Reporting

4 12.06.2012 Geschäftslogik in der Datenbank

Virtuelle ODBMS auf Basis RDBMS (DOAG Konferenz 2004)

Aufbau

• OO-ROWTYPE (ROWTYPE + DML, DEFAULT,

TO_STRING, DBMS_OUTPUT- Methoden, PK/UK-

Konstruktoren, ROW_LOCK)

• BO-Typen (Vererbung, Aggregation, Assoziation)

Verwendung

• Methoden statt üblicher DML- Anweisungen

• Datennormalisierung über RDBMS

• PK/UK- Konstruktoren - ziehen referenziertes

Objekt über relationale ID (DEREF- Analogon)

RDBMSRDBMSRDBMS

OO-ROWTYPESOO-ROWTYPESOO-ROWTYPES

BO-TYPESBO-TYPESBO-TYPESBO-TYPES

Generator

• Java-Class

• PL/SQL-Wrapper

• DDL-Trigger mit asynchroner Queue

5 12.06.2012 Geschäftslogik in der Datenbank

Tabelle und OO-Rowtype (Beispiel)

CREATE OR REPLACE TYPE ROW_STATUS UNDER GLOBAL.TYPE_OBJECT

( -- attributes

STATUS_ID NUMBER(12)

, KURZBEZEICHNUNG VARCHAR2(50)

, ERSTELLT_ZST DATE

, ERSTELLT_ID VARCHAR2(30)

, GEAENDERT_ZST DATE

, GEAENDERT_ID NUMBER(12)

, GEAENDERT_ZAEHLER NUMBER(10)

, BEZEICHNUNG VARCHAR2(200)

-- constructors

, CONSTRUCTOR FUNCTION ROW_STATUS RETURN SELF AS RESULT

, CONSTRUCTOR FUNCTION ROW_STATUS(IN_STATUS_ID NUMBER)

RETURN SELF AS RESULT

-- member functions

, MEMBER FUNCTION ROW_EXISTS(IN_STATUS_ID NUMBER) RETURN BOOLEAN

, OVERRIDING MEMBER FUNCTION compare(in_type1 GLOBAL.TYPE_OBJECT

,in_type2 GLOBAL.TYPE_OBJECT)

RETURN INTEGER

-- member procedures

, MEMBER PROCEDURE ROW_INSERT

, MEMBER PROCEDURE ROW_UPDATE

, MEMBER PROCEDURE ROW_MERGE

, MEMBER PROCEDURE ROW_SAVE

, MEMBER PROCEDURE ROW_DELETE

, MEMBER PROCEDURE ROW_SELECT(IN_STATUS_ID NUMBER)

, MEMBER PROCEDURE ROW_DEFAULT

, MEMBER PROCEDURE ROW_LOCK

, MEMBER PROCEDURE ROW_LOCK(IN_STATUS_ID NUMBER)

) NOT FINAL

CREATE OR REPLACE TRIGGER TBI$STATUS

BEFORE INSERT ON WPH.STATUS FOR EACH ROW

WHEN ( NEW.STATUS_ID IS NULL)

DECLARE

BEGIN

SELECT STATUS_SEQ.NEXTVAL

INTO :NEW.STATUS_ID

FROM DUAL;

END;

--------------------------------------------------------------------------------------------

CREATE OR REPLACE TRIGGER TBU$STATUS

BEFORE UPDATE ON WPH.STATUS FOR EACH ROW

BEGIN

:new.Geaendert_ID := SYS_CONTEXT('VPD', 'USERID');

:new.Geaendert_ZST := sysdate;

:new.Geaendert_Zaehler := :old.Geaendert_Zaehler + 1;

end;

6 12.06.2012 Geschäftslogik in der Datenbank

RETURNING clause (INSERT und UPDATE)

MEMBER PROCEDURE ROW_INSERT IS methodenname CONSTANT VARCHAR2(100) := 'WPH.ROW_STATUS.ROW_INSERT'; BEGIN

IF SYS_CONTEXT('TRACE','TRACE_LEVEL') >= GLOBAL.PA_TRACE.TRACE_TRACE THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_TRACE, methodenname, 'Parameters: '); END IF;

INSERT INTO WPH.STATUS ( STATUS_ID ,KURZBEZEICHNUNG ,BEZEICHNUNG ) VALUES ( SELF.STATUS_ID ,SELF.KURZBEZEICHNUNG ,SELF.BEZEICHNUNG ) RETURNING STATUS_ID ,KURZBEZEICHNUNG ,ERSTELLT_ZST ,ERSTELLT_ID ,GEAENDERT_ZST ,GEAENDERT_ID ,GEAENDERT_ZAEHLER ,BEZEICHNUNG INTO SELF.STATUS_ID ,SELF.KURZBEZEICHNUNG ,SELF.ERSTELLT_ZST ,SELF.ERSTELLT_ID ,SELF.GEAENDERT_ZST ,SELF.GEAENDERT_ID ,SELF.GEAENDERT_ZAEHLER ,SELF.BEZEICHNUNG ; EXCEPTION WHEN OTHERS THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_ERROR, methodenname, ' - Exception raised. ' ||SELF.TO_STRING() ||', SQLcode=' || to_char(SQLCODE) || ', ' || SQLERRM); RAISE; END;

7 12.06.2012 Geschäftslogik in der Datenbank

SAVE und MERGE

MEMBER PROCEDURE ROW_SAVE IS methodenname CONSTANT VARCHAR2(100) := 'WPH.ROW_STATUS.ROW_SAVE'; BEGIN

IF SYS_CONTEXT('TRACE','TRACE_LEVEL') >= GLOBAL.PA_TRACE.TRACE_TRACE THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_TRACE, methodenname, 'Parameters: '); END IF;

IF ROW_EXISTS(IN_STATUS_ID => SELF.STATUS_ID) THEN SELF.ROW_UPDATE; ELSE SELF.ROW_INSERT; END IF; EXCEPTION WHEN OTHERS THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_ERROR, methodenname, ' - Exception raised. ' ||SELF.TO_STRING() ||', SQLcode=' || to_char(SQLCODE) || ', ' || SQLERRM); RAISE; END;

---------------------------------------------------------------

MEMBER PROCEDURE ROW_MERGE IS methodenname CONSTANT VARCHAR2(100) := 'WPH.ROW_STATUS.ROW_MERGE'; BEGIN

IF SYS_CONTEXT('TRACE','TRACE_LEVEL') >= GLOBAL.PA_TRACE.TRACE_TRACE THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_TRACE, methodenname, 'Parameters: '); END IF;

MERGE INTO WPH.STATUS A USING ( SELECT SELF.STATUS_ID AS STATUS_ID ,SELF.KURZBEZEICHNUNG AS KURZBEZEICHNUNG ,SELF.BEZEICHNUNG AS BEZEICHNUNG FROM DUAL ) B ON (A.STATUS_ID = B.STATUS_ID) WHEN MATCHED THEN UPDATE SET KURZBEZEICHNUNG = B.KURZBEZEICHNUNG ,BEZEICHNUNG = B.BEZEICHNUNG WHEN NOT MATCHED THEN INSERT ( STATUS_ID ,KURZBEZEICHNUNG ,BEZEICHNUNG ) VALUES ( B.STATUS_ID ,B.KURZBEZEICHNUNG ,B.BEZEICHNUNG ); EXCEPTION WHEN OTHERS THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_ERROR, methodenname, ' - Exception raised. ' ||SELF.TO_STRING() ||', SQLcode=' || to_char(SQLCODE) || ', ' || SQLERRM); RAISE; END;

8 12.06.2012 Geschäftslogik in der Datenbank

Pessimistisches Locking - Default

MEMBER PROCEDURE ROW_LOCK IS methodenname CONSTANT VARCHAR2(100) := 'WPH.ROW_STATUS.ROW_LOCK'; v_lock NUMBER; BEGIN

IF SYS_CONTEXT('TRACE','TRACE_LEVEL') >= GLOBAL.PA_TRACE.TRACE_TRACE THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_TRACE, methodenname, 'Parameters: '); END IF;

SELECT GEAENDERT_ZAEHLER INTO v_lock FROM WPH.STATUS WHERE STATUS_ID = SELF.STATUS_ID FOR UPDATE ; IF SELF.GEAENDERT_ZAEHLER <> v_lock THEN SELF.ROW_SELECT( IN_STATUS_ID => SELF.STATUS_ID); END IF;

EXCEPTION WHEN OTHERS THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_ERROR, methodenname, ' - Exception raised. ' ||SELF.TO_STRING() ||', SQLcode=' || to_char(SQLCODE) || ', ' || SQLERRM); RAISE; END;

declare

i ROW_STATUS;

begin

i := ROW_STATUS(IN_STATUS_ID => 200);

...

i.ROW_LOCK();

end;

9 12.06.2012 Geschäftslogik in der Datenbank

Pessimistisches Locking mit PK oder UK

MEMBER PROCEDURE ROW_LOCK(IN_STATUS_ID NUMBER) IS methodenname CONSTANT VARCHAR2(300) := 'WPH.ROW_STATUS.ROW_LOCK(IN_STATUS_ID NUMBER)'; BEGIN

IF SYS_CONTEXT('TRACE','TRACE_LEVEL') >= GLOBAL.PA_TRACE.TRACE_TRACE THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_TRACE, methodenname, 'Parameters: ' ||'IN_STATUS_ID = '||IN_STATUS_ID||';' ); END IF;

SELECT STATUS_ID ,KURZBEZEICHNUNG ,ERSTELLT_ZST ,ERSTELLT_ID ,GEAENDERT_ZST ,GEAENDERT_ID ,GEAENDERT_ZAEHLER ,BEZEICHNUNG INTO SELF.STATUS_ID ,SELF.KURZBEZEICHNUNG ,SELF.ERSTELLT_ZST ,SELF.ERSTELLT_ID ,SELF.GEAENDERT_ZST ,SELF.GEAENDERT_ID ,SELF.GEAENDERT_ZAEHLER ,SELF.BEZEICHNUNG FROM WPH.STATUS WHERE STATUS_ID = IN_STATUS_ID FOR UPDATE ; EXCEPTION WHEN OTHERS THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_ERROR, methodenname, ' - Exception raised. ' ||'IN_STATUS_ID = '||IN_STATUS_ID||';' ||', SQLcode=' || to_char(SQLCODE) || ', ' || SQLERRM); RAISE; END;

declare

i ROW_STATUS;

begin

i := ROW_STATUS();

i.ROW_LOCK(IN_STATUS_ID => 200);

end;

10 12.06.2012 Geschäftslogik in der Datenbank

Optimistisches Locking - UPDATE

MEMBER PROCEDURE ROW_UPDATE IS methodenname CONSTANT VARCHAR2(100) := 'WPH.ROW_STATUS.ROW_UPDATE'; BEGIN

IF SYS_CONTEXT('TRACE','TRACE_LEVEL') >= GLOBAL.PA_TRACE.TRACE_TRACE THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_TRACE, methodenname, 'Parameters: '); END IF;

UPDATE WPH.STATUS SET KURZBEZEICHNUNG = SELF.KURZBEZEICHNUNG ,BEZEICHNUNG = SELF.BEZEICHNUNG WHERE STATUS_ID = SELF.STATUS_ID AND GEAENDERT_ZAEHLER = SELF.GEAENDERT_ZAEHLER RETURNING STATUS_ID ,KURZBEZEICHNUNG ,ERSTELLT_ZST ,ERSTELLT_ID ,GEAENDERT_ZST ,GEAENDERT_ID ,GEAENDERT_ZAEHLER ,BEZEICHNUNG INTO SELF.STATUS_ID ,SELF.KURZBEZEICHNUNG ,SELF.ERSTELLT_ZST ,SELF.ERSTELLT_ID ,SELF.GEAENDERT_ZST ,SELF.GEAENDERT_ID ,SELF.GEAENDERT_ZAEHLER ,SELF.BEZEICHNUNG ;

IF SQL%ROWCOUNT <> 1 THEN GLOBAL.RAISE(-20999); -- Der Datensatz hat sich zwischenzeitlich geändert END IF;

EXCEPTION WHEN OTHERS THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_ERROR, methodenname, ' - Exception raised. ' ||SELF.TO_STRING() ||', SQLcode=' || to_char(SQLCODE) || ', ' || SQLERRM); RAISE; END;

11 12.06.2012 Geschäftslogik in der Datenbank

Optimistisches Locking - DELETE

MEMBER PROCEDURE ROW_DELETE

IS

methodenname CONSTANT VARCHAR2(100) := 'WPH.ROW_STATUS.ROW_DELELE';

BEGIN

IF SYS_CONTEXT('TRACE','TRACE_LEVEL') >= GLOBAL.PA_TRACE.TRACE_TRACE THEN

GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_TRACE, methodenname, 'Parameters: ');

END IF;

DELETE FROM WPH.STATUS

WHERE STATUS_ID = SELF.STATUS_ID

AND GEAENDERT_ZAEHLER = SELF.GEAENDERT_ZAEHLER;

IF SQL%ROWCOUNT <> 1 THEN

GLOBAL.RAISE(-20999); -- Der Datensatz hat sich zwischenzeitlich geändert

END IF;

EXCEPTION

WHEN OTHERS THEN

GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_ERROR, methodenname, ' - Exception raised. '

||SELF.TO_STRING()

||', SQLcode=' || to_char(SQLCODE) || ', ' || SQLERRM);

RAISE;

END;

12 12.06.2012 Geschäftslogik in der Datenbank

Variablen und OO-ROWTYPE

declare

s WPH.STATUS.KURZBEZEICHNUNG%TYPE;

begin

SELECT s.kurzbezeichnung

INTO s

FROM WPH.STATUS s

WHERE s.STATUS_ID=200;

end;

declare

s WPH.ROW_STATUS;

begin

s := WPH.ROW_STATUS(IN_STATUS_ID => 200);

end;

declare

s VARCHAR2(50);

begin

SELECT s.kurzbezeichnung

INTO s

FROM WPH.STATUS s

WHERE s.sTATUS_ID=200;

end;

declare

s WPH.STATUS%ROWTYPE;

begin

SELECT *

INTO s

FROM WPH.STATUS s

WHERE s.sTATUS_ID=200;

end;

13 12.06.2012 Geschäftslogik in der Datenbank

Arbeiten mit OO-ROWTYPE

declare

i ROW_STATUS;

begin

i := ROW_STATUS(IN_STATUS_ID => 200);

i.DBMS_OUTPUT;

i.KURZBEZEICHNUNG := 'Eingestellt';

i.ROW_UPDATE;

i.DBMS_OUTPUT;

end;

<ROW_STATUS>

<OBJECT_TYPE_NAME>WPH.ROW_STATUS</OBJECT_TYPE_NAME>

<STATUS_ID>200</STATUS_ID>

<KURZBEZEICHNUNG>Einstellung</KURZBEZEICHNUNG>

<ERSTELLT_ZST>12.07.02</ERSTELLT_ZST>

<ERSTELLT_ID>-2</ERSTELLT_ID>

<GEAENDERT_ZST>14.08.04</GEAENDERT_ZST>

<GEAENDERT_ID>1469</GEAENDERT_ID>

<GEAENDERT_ZAEHLER>2</GEAENDERT_ZAEHLER>

<BEZEICHNUNG>ORDERAUSFUEHRUNG-STATUS</BEZEICHNUNG>

</ROW_STATUS>

<ROW_STATUS>

<OBJECT_TYPE_NAME>WPH.ROW_STATUS</OBJECT_TYPE_NAME>

<STATUS_ID>200</STATUS_ID>

<KURZBEZEICHNUNG>Eingestellt</KURZBEZEICHNUNG>

<ERSTELLT_ZST>12.07.02</ERSTELLT_ZST>

<ERSTELLT_ID>-2</ERSTELLT_ID>

<GEAENDERT_ZST>15.06.10</GEAENDERT_ZST>

<GEAENDERT_ID>907</GEAENDERT_ID>

<GEAENDERT_ZAEHLER>3</GEAENDERT_ZAEHLER>

<BEZEICHNUNG>ORDERAUSFUEHRUNG-STATUS</BEZEICHNUNG>

</ROW_STATUS>

14 12.06.2012 Geschäftslogik in der Datenbank

Gattungsstamm – Input Daten

G DE000AAR0082AAR0081900000640329 00"GD090 09062010"GD100 01"GD100A 1"GD160 004"GD161 DE"GD170 EO

"GD171 EUR"GD172 EUR"GD190 PD"GD195 227"GD196 1"GD198A SEC"GD198B 2000"GD198C 2003"GD198D ZZZZ"GD198E ZZZZ"GD198F

E302"GD198G M401"GD200 00025"GD201 DE03472 "GD205B KA05"GD211 1"GD212 703"GD213 25"GD214 22"GD215A

J"GD217 AAC"GD218 J"GD218A J"GD218B J"GD218C J"GD220 142"GD220A 004"GD220C

183"GD225 A"GD226 60"GD227 1"GD228 0413"GD230 MTH"GD234 1"GD240 804110"GD260 AAREAL BANK MTN.HPF.S.67 "GD270A Aareal

Bank AG "GD270B MTN-HPF.S.67 v.2010(2013) "GD280A Serie 67 v. 2010 (2013) "GD290 16092010"GD290A

16092010"GD300 16092013"GD312 6"GD321 10"GD322 16062010"GD323 15092013"GD388A

686665"GD388PIDE0006866650"GD400 03"GD410 9"GD420 7"GD423 J"GD424 B"GD430 099"GD440 2"GD455A 000001000000000000"GD455E

1"GD473 ²NOM=1000,W=EUR; "GD481A 05"GD483 1"GD500 84"GD504A J"GD505B 25000000000"GD505E

2"GD507 0550000"GD545 1"GD545A 2"GD546 09062010"GD571 J"GD572 J"GD621 099"GD622 DE000AAR0082"GD622PWAAR008"GD630A

000000500000000000"GD630B EUR"GD650A 000000500000000000"GD660 16062010"GD663A N"GD663D N"GD669 0000997590000"GD670A

EUR"GD670B %"GD672 1"GD685 DTFSFB"GD697 2B"GD776 3"GD801A 0001750000000"GD805 F"GD810 093"GD811 1"GD812 16"GD812A

16"GD813 SEPT"GD813A SEPT"GD815 0092"GD815A 0044109589"GD819 2"GD821B 09"GD822 01"GD841 2"GD861A

000000100000000000"GD862 16092013"GD910 16092013"GD924 N"GD970G 01"GD986 ²deutsches Recht

G DE000AAR0082AAR0081909920640329 00"GV992 ²0660/J/ / / / / / / / / / / / / ²0348/J/ / / / / / / / / / / / / ²2597/J/ / / / / / / / / / / / /

G DE000AAR0082AAR0081909950640329 00"GV995 ²0660/ / / / / / / / / /J/ / / / ²0348/ / / / / / / / / / /J/ / / ²2597/ / / / / / / / / / /J/ / /

E NO00030753019065612010060932000 00"ED001 2"ED002A 1"ED004A DD"ED023 1"ED024A 01012009"ED025A 31122009"ED190 02

G NO00030753019065611910000603643 00"GD090 29062010"GD260 PETROLIA DRILLING NK 5"GD270A Petrolia Drilling ASA "GD270B

Navne-Aksjer NK 5 "GD460A 000000005000000000

H NO00030753019065612010032905600200"HD008 28062010"HD015 1300

U NO00030753019065612010060940500 00"UD001 1"UD002A 1"UD005 1"UD006 1"UD007 4"UD008A AZ"UD010A ST "UD010C

0000010000000"UD010D 0000000100000000"UD011A ST "UD011C 0000100000000"UD011D

0000000010000000"UD021 906561"UD021PINO0003075301"UD025 29062010²ca. "UD034 28062010"UD078 20"UD087 049"U

D190 02"UD460A 000000000500000000"UD460B 000000005000000000

15 12.06.2012 Geschäftslogik in der Datenbank

Gattungsstamm – Datenbank Model

16 12.06.2012 Geschäftslogik in der Datenbank

Schwergewichtiger TYPE

CREATE OR REPLACE TYPE TYPE_GATTUNG AUTHID CURRENT_USER UNDER GLOBAL.TYPE_OBJECT ( -- Attributes id NUMBER(12) , isin CHAR(12) , wkn CHAR(6) , sh NUMBER(2) , geloescht DATE , name VARCHAR2(80) , instrument VARCHAR2(80) , fids WP.TABLE_WMFID , ertraege WP.TABLE_ERTRAG , kapitals WP.TABLE_KAPITAL , ohc WP.TABLE_GATTUNG_OHC , hauptversammlung WP.TABLE_HAUPTVERSAMMLUNG , bogenerneuerung WP.TABLE_BOGENERNEUERUNG , umtausch WP.TABLE_UMTAUSCH , verlosung WP.TABLE_VERLOSUNG , termin WP.TABLE_GATTUNG_TERMIN , opposition WP.TABLE_OPPOSITION , ifp WP.TABLE_WMFID , NWKN VARCHAR2(4000) -- Nationale WKN -- Methods , CONSTRUCTOR FUNCTION TYPE_GATTUNG RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_GATTUNG(in_id NUMBER) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_GATTUNG(IN_ID NUMBER, IN_DATUM DATE) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_GATTUNG(in_isin VARCHAR2, in_sh NUMBER DEFAULT 0) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_GATTUNG(in_wkn VARCHAR2, in_sh NUMBER DEFAULT 0) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_GATTUNG(in_wkn VARCHAR2, in_sh NUMBER, in_datum DATE) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_GATTUNG(in_isin VARCHAR2, in_wkn VARCHAR2, in_sh NUMBER DEFAULT 0, in_geloescht DATE DEFAULT NULL) RETURN SELF AS RESULT

, CONSTRUCTOR FUNCTION TYPE_GATTUNG(in_isin VARCHAR2, in_wkn VARCHAR2, in_instrument VARCHAR2) RETURN SELF AS RESULT

, MEMBER PROCEDURE add_ertrag(in_ertrag WP.TYPE_ERTRAG) , MEMBER PROCEDURE add_hauptversammlung(in_hauptversammlung WP.TYPE_HAUPTVERSAMMLUNG) , MEMBER PROCEDURE add_bogenerneuerung(in_bogenerneuerung WP.TYPE_BOGENERNEUERUNG) , MEMBER PROCEDURE add_kapital(in_kapital WP.TYPE_KAPITAL) , MEMBER PROCEDURE add_umtausch(in_umtausch WP.TYPE_UMTAUSCH) , MEMBER PROCEDURE add_verlosung(in_verlosung WP.TYPE_VERLOSUNG) , MEMBER PROCEDURE add_ohc(in_ohc WP.TYPE_GATTUNG_OHC) , MEMBER PROCEDURE add_termin(in_termin WP.TYPE_GATTUNG_TERMIN) , MEMBER PROCEDURE add_opposition(in_opposition WP.TYPE_OPPOSITION)

, MEMBER PROCEDURE INIT_KAPITAL_DETAIL(SELF IN OUT TYPE_GATTUNG) , MEMBER FUNCTION GET_KAPITAL_DETAIL(SELF IN OUT TYPE_GATTUNG) RETURN WP.TABLE_KAPITAL , MEMBER PROCEDURE INIT_FID_DETAIL(SELF IN OUT TYPE_GATTUNG) , MEMBER FUNCTION GET_FID_DETAIL(SELF IN OUT TYPE_GATTUNG) RETURN WP.TABLE_WMFID , MEMBER PROCEDURE INIT_SCD_FIDS(IN_DATUM DATE DEFAULT NULL) , MEMBER PROCEDURE INIT_OHC(IN_BOERSENPLATZ_ID VARCHAR2)

,…

) NOT FINAL

17 12.06.2012 Geschäftslogik in der Datenbank

Schwergewichtiger TYPE (Fortsetzung)

CREATE OR REPLACE TYPE TABLE_ERTRAG AS TABLE OF WP.TYPE_ERTRAG;

------------------------------------------------------------------------------------------------------------------------

CREATE OR REPLACE TYPE TYPE_ERTRAG UNDER WP.ROW_ERTRAG_BASE ( -- Attributes id NUMBER(12) , fids WP.TABLE_WMFID

-- Methods , CONSTRUCTOR FUNCTION TYPE_ERTRAG RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_ERTRAG(in_wmdaten WP.TYPE_WMDATEN) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_ERTRAG(OBJECT_TYPE_NAME VARCHAR2, ID NUMBER, BID_NR VARCHAR2, DATUM DATE, FIDS WP.TABLE_WMFID) RETURN SELF AS RESULT

, CONSTRUCTOR FUNCTION TYPE_ERTRAG(BID_NR VARCHAR2, DATUM DATE, FIDs WP.TABLE_WMFID) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_ERTRAG(in_BID_NR VARCHAR2, in_DATUM VARCHAR2, in_FIDs WP.TABLE_WMFID) RETURN SELF AS RESULT

, CONSTRUCTOR FUNCTION TYPE_ERTRAG(IN_ERTRAG_BASE_ID NUMBER, IN_DATUM DATE DEFAULT NULL) RETURN SELF AS RESULT , MEMBER PROCEDURE INIT_SCD_FIDS(IN_DATUM DATE DEFAULT NULL) , OVERRIDING MEMBER FUNCTION compare(in_type1 GLOBAL.TYPE_OBJECT, in_type2 GLOBAL.TYPE_OBJECT) RETURN INTEGER , MEMBER PROCEDURE getDBid(in_gattung_id NUMBER) , MEMBER PROCEDURE save(in_gattung_id NUMBER,IN_DATUM DATE DEFAULT SYSDATE) , MEMBER FUNCTION TO_VF1 RETURN GLOBAL.TABLE_VARCHAR2 ) NOT FINAL

---------------------------------------------------------------------------------------------------------------------------

CREATE OR REPLACE TYPE ROW_ERTRAG_BASE UNDER GLOBAL.TYPE_OBJECT (-- attributes ERTRAG_BASE_ID NUMBER(12) , GATTUNG_BASE_ID NUMBER(12) , BID_NR VARCHAR2(5) , DATUM DATE , ERSTELLT_ZST DATE , GEAENDERT_ZST DATE , ERSTELLT_ID NUMBER(12) , GEAENDERT_ID NUMBER(12) , ERSTELLT_IP VARCHAR2(30) , GEAENDERT_IP VARCHAR2(30) , GEAENDERT_ZAEHLER NUMBER(10)

-- define constructors , CONSTRUCTOR FUNCTION ROW_ERTRAG_BASE RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION ROW_ERTRAG_BASE(ERTRAG_BASE_ID NUMBER, GATTUNG_BASE_ID NUMBER, BID_NR

, …

) NOT FINAL

18 12.06.2012 Geschäftslogik in der Datenbank

Schwergewichtiger TYPE & Load Balancing

MEMBER PROCEDURE INIT_KAPITAL_DETAIL(SELF IN OUT TYPE_GATTUNG) IS methodenname CONSTANT VARCHAR2(300) := 'WP.'||$$PLSQL_UNIT||'.INIT_KAPITAL_DETAIL'; FUNCTION parm RETURN VARCHAR2 IS BEGIN RETURN substr( 'Parameter: ' || CHR(10) || 'SELF:' || SELF.TO_STRING(),1,32760); END; BEGIN IF SYS_CONTEXT('TRACE','TRACE_LEVEL') >= GLOBAL.PA_TRACE.TRACE_TRACE THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_TRACE, methodenname, parm()); END IF;

SELF.kapitals := WP.TABLE_KAPITAL(); FOR rec IN (SELECT d.kapital_base_id FROM WP.Kapital_Base d WHERE d.gattung_base_id = SELF.id ORDER BY datum ) LOOP SELF.kapitals.EXTEND; SELF.kapitals(SELF.kapitals.LAST) := WP.TYPE_KAPITAL(in_kapital_base_id => rec.kapital_base_id); END LOOP;

EXCEPTION WHEN OTHERS THEN GLOBAL.pa_trace.TRACE( GLOBAL.pa_trace.TRACE_ERROR, methodenname, parm()||CHR(10)|| ', SQLcode=' || to_char(SQLCODE) || ', ' || SQLERRM); RAISE; END;

--------------------------------------------------------------- MEMBER FUNCTION GET_KAPITAL_DETAIL(SELF IN OUT TYPE_GATTUNG) RETURN WP.TABLE_KAPITAL IS methodenname CONSTANT VARCHAR2(300) := 'WP.'||$$PLSQL_UNIT||'.GET_KAPITAL_DETAIL'; FUNCTION parm RETURN VARCHAR2 IS BEGIN RETURN substr('Parameter: ' || CHR(10) || 'SELF:' || SELF.TO_STRING(),1,32760); END; BEGIN IF SYS_CONTEXT('TRACE','TRACE_LEVEL') >= GLOBAL.PA_TRACE.TRACE_TRACE THEN GLOBAL.PA_TRACE.TRACE( GLOBAL.PA_TRACE.TRACE_TRACE, methodenname, parm()); END IF;

IF SELF.kapitals IS NULL THEN

SELF.INIT_KAPITAL_DETAIL();

END IF; RETURN SELF.kapitals; EXCEPTION WHEN OTHERS THEN GLOBAL.pa_trace.TRACE( GLOBAL.pa_trace.TRACE_ERROR, methodenname, parm()||CHR(10)|| ', SQLcode=' || to_char(SQLCODE) || ', ' || SQLERRM); RAISE; END;

19 12.06.2012 Geschäftslogik in der Datenbank

Fliegengewichtiger COMP

CREATE OR REPLACE TYPE COMP_GATTUNG UNDER GLOBAL.TYPE_OBJECT ( -- Attributes GATTUNG_BASE_ID NUMBER , WKN CHAR(6) , ISIN CHAR(12) , SH NUMBER(2) , NAME VARCHAR2(80) , INSTRUMENT VARCHAR2(80) , GELOESCHT DATE

-- Methods , CONSTRUCTOR FUNCTION COMP_GATTUNG RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION COMP_GATTUNG(IN_GATTUNG_BASE_ID NUMBER) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION COMP_GATTUNG(IN_ISIN VARCHAR2, IN_SH NUMBER DEFAULT 0) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION COMP_GATTUNG(IN_WKN VARCHAR2, IN_SH NUMBER DEFAULT 0) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION COMP_GATTUNG(IN_ISIN VARCHAR2, IN_WKN VARCHAR2, IN_SH NUMBER) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION COMP_GATTUNG(IN_SECURITY_ID VARCHAR2, IN_ID_SOURCE VARCHAR2) RETURN SELF AS RESULT

, MEMBER FUNCTION GET_ABRECHNUNGS_WAEHRUNG_ISO(IN_BOERSENPLATZ_ID VARCHAR2) RETURN VARCHAR2 , MEMBER FUNCTION GET_ABRECHNUNGS_WAEHRUNG_ID(IN_BOERSENPLATZ_ID VARCHAR2) RETURN NUMBER , MEMBER FUNCTION GET_ABRECHNUNGS_WAEHRUNG_ISO RETURN VARCHAR2 , MEMBER FUNCTION GET_HANDELS_WAEHRUNG_ISO(IN_BOERSENPLATZ_ID VARCHAR2) RETURN VARCHAR2 , MEMBER FUNCTION GET_HANDELS_WAEHRUNGEN_ISO(IN_BOERSENPLATZ_ID VARCHAR2) RETURN BBS.TAB_ROW_WAEHRUNG , MEMBER FUNCTION GET_RIC RETURN VARCHAR2 , MEMBER FUNCTION GET_RIC(IN_BOERSENPLATZ_ID VARCHAR2) RETURN VARCHAR2 , MEMBER FUNCTION GET_SEDOL RETURN VARCHAR2 , MEMBER FUNCTION GET_CUSIP RETURN VARCHAR2 , MEMBER FUNCTION GET_EMITTENT_NR RETURN VARCHAR2 , MEMBER FUNCTION GET_HEIMATLAND_ISO RETURN VARCHAR2 , MEMBER FUNCTION GET_HEIMATBOERSE_ID RETURN VARCHAR2 , MEMBER FUNCTION GET_LETZTER_HANDELSTAG(IN_BOERSENPLATZ_ID VARCHAR2) RETURN DATE , MEMBER FUNCTION IS_MIFID_RELEVANT RETURN BOOLEAN , MEMBER FUNCTION IS_DAX RETURN BOOLEAN , MEMBER FUNCTION IS_MDAX RETURN BOOLEAN , MEMBER FUNCTION IS_SDAX RETURN BOOLEAN , MEMBER FUNCTION IS_TECDAX RETURN BOOLEAN , MEMBER FUNCTION IS_STOXX RETURN BOOLEAN , MEMBER FUNCTION IS_HANDELBAR(IN_LAND_ISO VARCHAR2) RETURN BOOLEAN , MEMBER FUNCTION IS_HANDELBAR(IN_BOERSENPLATZ_ID VARCHAR2) RETURN BOOLEAN , MEMBER FUNCTION IS_HANDELBAR_FH(IN_BOERSENPLATZ_ID VARCHAR2) RETURN BOOLEAN , MEMBER FUNCTION IS_INVESTRO RETURN BOOLEAN , MEMBER FUNCTION IS_ZERTIFIKAT RETURN BOOLEAN , MEMBER FUNCTION IS_WARRANT RETURN BOOLEAN , MEMBER FUNCTION IS_FOND RETURN BOOLEAN , MEMBER FUNCTION IS_BEGO_FOND RETURN BOOLEAN , MEMBER FUNCTION IS_EHF RETURN BOOLEAN , MEMBER FUNCTION IS_DEF RETURN BOOLEAN , … ) NOT FINAL

20 12.06.2012 Geschäftslogik in der Datenbank

Schwergewichtiger TYPE

CREATE OR REPLACE TYPE TYPE_KUNDE UNDER BBS.ROW_KUNDE ( -- attributes DEPOT BBS.TABLE_DEPOT, KONTEN BBS.TABLE_KONTO, KONTEN_BBS BBS.TABLE_KONTO_BBS,

land VARCHAR2(35), nationalitaet VARCHAR2(35), rechtsform VARCHAR2(105), branche VARCHAR2(105), betreuer1 VARCHAR2(35), betreuer2 VARCHAR2(35), betreuer3 VARCHAR2(35), betreuer4 VARCHAR2(35), stammkreis VARCHAR2(35)

-- define constructors , CONSTRUCTOR FUNCTION TYPE_KUNDE RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_KUNDE(IN_STAMMNR VARCHAR2) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_KUNDE(IN_UNTERDEPOTID NUMBER) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_KUNDE(IN_KUNDENID NUMBER, IN_KONTOID NUMBER) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_KUNDE(IN_DEPOTNUMMER CHAR, IN_REFERENZNUMMER NUMBER) RETURN SELF AS RESULT --------------------------------------------------------------- -- static functions instead of constructors -- duplicate signature problem in Java , STATIC FUNCTION CONSTRUCTOR_TYPE_KUNDE(IN_KUNDENID NUMBER) RETURN BBS.TYPE_KUNDE , STATIC FUNCTION CONSTRUCTOR_KONTONUMMER(IN_KONTONUMMER VARCHAR2) RETURN BBS.TYPE_KUNDE , STATIC FUNCTION CONSTRUCTOR_KONTO_BBS_ID(IN_KONTO_BBS_ID NUMBER) RETURN BBS.TYPE_KUNDE

-- define member functions , MEMBER PROCEDURE ROW_SELECT(IN_STAMMNR VARCHAR2) , MEMBER PROCEDURE ROW_SELECT(IN_KUNDENID NUMBER, IN_VERSION NUMBER)

, MEMBER PROCEDURE init_text_fields , MEMBER PROCEDURE INIT_DEPOT(SELF IN OUT TYPE_KUNDE, IN_REFERENZNUMMER NUMBER DEFAULT NULL)

, MEMBER PROCEDURE INIT_DEPOT(SELF IN OUT TYPE_KUNDE, IN_DISPLAY_ID NUMBER, IN_REFERENZNUMMER NUMBER DEFAULT NULL)

, MEMBER PROCEDURE INIT_KONTEN(SELF IN OUT TYPE_KUNDE)

, …

) NOT FINAL

21 12.06.2012 Geschäftslogik in der Datenbank

Fliegengewichtiger COMP

CREATE OR REPLACE TYPE COMP_KUNDE UNDER GLOBAL.TYPE_OBJECT

( -- Attributes

KUNDE_ID NUMBER(12)

, STAMMNUMMER CHAR(10)

, INHABER VARCHAR2(35)

, SPRACHE_ID NUMBER(12)

-- Methods

, CONSTRUCTOR FUNCTION COMP_KUNDE RETURN SELF AS RESULT

, CONSTRUCTOR FUNCTION COMP_KUNDE(in_kunde_id NUMBER) RETURN SELF AS RESULT

, CONSTRUCTOR FUNCTION COMP_KUNDE(in_stammnummer CHAR) RETURN SELF AS RESULT

, CONSTRUCTOR FUNCTION COMP_KUNDE(in_unterdepot_id NUMBER) RETURN SELF AS RESULT

) NOT FINAL

22 12.06.2012 Geschäftslogik in der Datenbank

Mischung OO-Type und relationale FK ID

Analogon zur DEREF in ODBMS kann man mit dem FK eines Type den anderen

Type instanzieren

declare

b wph.ROW_BOERSE;

h wph.ROW_HANDELSSYSTEM;

begin

b := wph.ROW_BOERSE('194');

h := wph.ROW_HANDELSSYSTEM(b.HANDELSSYSTEM_ID);

end;

23 12.06.2012 Geschäftslogik in der Datenbank

Wie programmieren wir in PL/SQL

-- Allocation ermitteln

FOR rec_alloc IN (SELECT g.COLUMN_VALUE AS xml

FROM TABLE (XMLSEQUENCE(rec_order.XML.EXTRACT('Order/Allocations/Allocation'))) g)

LOOP

-- Neue Allocation anlegen

t_allocation := NEW WPH.TYPE_ALLOCATION ( IN_KUNDE_ID => t_ob.KUNDE_ID

, IN_ANNAHMEART_ID => t_ob.ANNAHMEART_ID

, IN_ALLOC_IDENT => t_ob.ORDER_NR_EXTERN

, ...);

-- Order hinzufuegen

t_allocation.ADD_ORDER(IN_ORDER_BUCH_ID => t_ob.ORDER_BUCH_ID);

-- Client Account ermitteln

v_client_account := GLOBAL.PA_XML.EXTRACT_STRING(rec_alloc.XML, 'Allocation/ClientAccount');

-- Stueckzahl ermitteln

v_stueckzahl := GLOBAL.PA_XML.EXTRACT_NUMBER(rec_alloc.XML, 'Allocation/Stueckzahl');

IF v_stueckzahl IS NOT NULL THEN

-- Allocation hinzufuegen

t_allocation.ADD_ALLOCATION(IN_CLIENT_ACCOUNT => v_client_account

, IN_STUECKZAHL => GLOBAL.PA_XML.EXTRACT_NUMBER(rec_alloc.XML, 'Allocation/Stueckzahl')

, IN_KURS => NULL);

ELSE

-- Prozentsatz ermitteln

v_prozentsatz := GLOBAL.PA_XML.EXTRACT_NUMBER(rec_alloc.XML, 'Allocation/Prozentsatz');

-- Allocation hinzufuegen

t_allocation.ADD_ALLOCATION(IN_CLIENT_ACCOUNT => v_client_account

, IN_PROZENTSATZ => v_prozentsatz);

END IF;

END LOOP;

-- Allocation einstellen

t_allocation.EINSTELLEN();

24 12.06.2012 Geschäftslogik in der Datenbank

Wie programmieren wir in PL/SQL

-- zentrale Schnittstelle zum Steuermodul

PROCEDURE STEUER_BERECHNUNG(...)

IS

t_steuer BBS.TYPE_STEUER;

BEGIN

-- geschäftsbedingt Instanzierung

IF ....GESCHAEFTSART = 'KKZ' THEN

t_steuer := NEW BBS.TYPE_STEUER_KKZ(...)

ELSIF ....GESCHAEFTSART = 'WPK' THEN

t_steuer := NEW BBS.TYPE_STEUER_WPK(...)

ELSIF <weitere Geschäftsbereiche> THEN

t_steuer := NEW BBS.TYPE_STEUER_XXX(...)

END IF;

-- Aufruf der Steuerverrechnung

t_steuer.BERECHNE_STEUERN;

END;

25 12.06.2012 Geschäftslogik in der Datenbank

Unsere Leitsätze

"Der einfache und klare Zweck sowie Prinzipien

bedingen komplexes und intelligentes Verhalten".

"Komplexe Regeln und Vorschriften

bedingen einfaches und dummes Verhalten".

Dee Hock, Designer VISA-Systems 1960-1970

Man sollte alles so einfach wie

möglich machen, aber nicht einfacher Albert Einstein

Ein System erreicht Perfektion nicht,

wenn nichts weiter hinzugefügt werden kann,

sondern wenn nichts weiter entfernt werden kann. ???

26 12.06.2012 Geschäftslogik in der Datenbank

Q&A

Vielen Dank !