Ich versuche, die Geschäftslogik einer Intranet-C # -Webanwendung in der Datenbank zu duplizieren, damit andere Datenbanken darauf zugreifen und nach denselben Regeln arbeiten können. Diese "Regel" scheint ohne Hacks schwierig zu implementieren zu sein.
CREATE TABLE CASE_STAGE
(
ID NUMBER(9) PRIMARY KEY NOT NULL,
STAGE_ID NUMBER(9) NOT NULL,
CASE_PHASE_ID NUMBER(9) NOT NULL,
DATE_CREATED TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP NOT NULL,
END_REASON_ID NUMBER(9),
PREVIOUS_CASE_STAGE_ID NUMBER(9),
"CURRENT" NUMBER(1) NOT NULL,
DATE_CLOSED TIMESTAMP(6) DEFAULT NULL
);
und
CREATE TABLE CASE_RECOMMENDATION
(
CASE_ID NUMBER(9) NOT NULL,
RECOMMENDATION_ID NUMBER(9) NOT NULL,
"ORDER" NUMBER(9) NOT NULL,
DATE_CREATED TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP NOT NULL,
CASE_STAGE_ID NUMBER(9) NOT NULL
);
ALTER TABLE CASE_RECOMMENDATION ADD (
CONSTRAINT SYS_C00000
PRIMARY KEY
(CASE_ID, RECOMMENDATION_ID));
Die Geschäftslogik kann wie folgt zusammengefasst werden
When Inserting into CASE_STAGE
If CASE_STAGE.STAGE_ID = 1646
THEN
CASE_STAGE.PREVIOUS_STAGE_ID must be found in CASE_RECOMMENDATION.CASE_STAGE_ID
Kann diese Logik in einer Check-Einschränkung enthalten sein oder ist ein hässlicher Trigger der einzige Weg?
Bearbeiten:
- Für alle Werte von CASE_STAGE.STAGE_ID muss der Wert für PREVIOUS_STAGE_ID in CASE_STAGE.ID gefunden werden
- Die Anwendung erlaubt keine Löschungen aus CASE_RECOMMENDATION, wenn sie nicht mehr CURRENT ist (dh wenn der Wert von CASE_STAGE.CURRENT 0 ist, ist diese Stufe geschlossen und kann nicht mehr geändert werden, wenn = 1, ist dies die Stufe oder Zeile, die aktiv ist und kann jetzt geändert werden.)
Bearbeiten: Die Verwendung all der hervorragenden Ideen und Kommentare hier ist eine funktionierende Lösung für dieses Problem
CREATE MATERIALIZED VIEW LOG ON CASE_STAGE
TABLESPACE USERS
STORAGE (
BUFFER_POOL DEFAULT
)
NOCACHE
LOGGING
NOPARALLEL
WITH ROWID;
CREATE MATERIALIZED VIEW LOG ON CASE_RECOMMENDATION
TABLESPACE USERS
STORAGE (
BUFFER_POOL DEFAULT
)
NOCACHE
LOGGING
NOPARALLEL
WITH ROWID;
CREATE MATERIALIZED VIEW CASE_RECOMMENDATION_MV REFRESH FAST ON COMMIT AS
SELECT
cr.ROWID cr_rowid, --necessary for fast refresh
cs.ROWID cs_rowid, --necessary for fast refresh
cr.case_id,
cs.stage_id,
cr.recommendation_id
cr.case_stage_id,
cs.previous_case_stage_id
FROM CASE_RECOMMENDATION cr,
case_stage cs
WHERE cs.previous_case_stage_id = cr.case_stage_id (+)
AND CS.PREVIOUS_CASE_STAGE_ID IS NOT NULL
AND EXTRACT (YEAR FROM CS.DATE_CREATED) > 2010 --covers non conforming legacy data
AND CR.RECOMMENDATION_ID IS NULL
AND cs.stage_id =1646;
--this last line excludes everything but problem cases due to the outer join
ALTER TABLE CASE_RECOMMENDATION_MV ADD CONSTRAINT CASE_RECOMMENDATION_ck CHECK (
(previous_case_stage_id IS NOT NULL AND case_stage_id IS NOT NULL)
);
Beim Einfügen einer 1646-Stufe unter Verwendung vorhandener Pakete ohne Empfehlung war der Fehler
ORA-12008: error in materialized view refresh path
ORA-02290: check constraint (APPBASE.CASE_RECOMMENDATION_MV_C01) violated
ORA-06512: at line 49
Job erledigt! Nicht wofür eine materialisierte Ansicht gedacht war, sondern besser als ein Auslöser.
quelle
CASE_RECOMMENDATION.CASE_STAGE_ID
einzigartig?1646
? Ist es eine Option, das Design zu ändern (Tabelle in zwei Teile zu teilen)?Antworten:
Wenn Sie komplexe Einschränkungen haben, die Sie "unsichtbar" in der Datenbank anwenden möchten, können Sie dies tun, indem Sie eine materialisierte Ansicht erstellen und dann Einschränkungen darauf anwenden.
In diesem Fall können Sie es ein MV-Außenverbindungs Verwendung
CASE_RECOMMENDATION.CASE_STAGE_ID
zuCASE_STAGE.PREVIOUS_CASE_STAGE_ID
. Es sollte dann überprüft werden, ob keines von diesen null ist, wenn dieCASE_STAGE.STAGE_ID = 1646
, wie folgt:Die Prüfbedingung für das MV wird nur aufgerufen, wenn es aktualisiert wird. Damit dies erfolgreich funktioniert, müssen Sie sicherstellen, dass dies in COMMIT erfolgt. Dies erhöht Ihre Festschreibungszeitverarbeitung, sodass Sie Folgendes berücksichtigen müssen:
Da diese Lösung die Einschränkungen in der SQL-Schicht implementiert, werden einige der in der prozeduralen Lösung diskutierten Parallelitätsprobleme überwunden.
AKTUALISIEREN
Wie von Vincent hervorgehoben, kann die Größe des MV reduziert werden, indem nur die Zeilen mit stage_id = 1646 eingeschlossen werden. Es ist möglicherweise möglich, die Abfrage neu zu schreiben, um keine Zeilen zu verbrauchen, aber ich kann mir nicht vorstellen, wie ich das richtig machen soll jetzt:
quelle
Wenn dies
CASE_RECOMMENDATION.CASE_STAGE_ID
eindeutig ist, können Sie die referenzielle Integrität mit einer virtuellen Spalte (11g +) verwenden, um sie bedingt zu machen:Lass uns nachsehen:
quelle
Es ist bewundernswert, Geschäftslogik in die Datenbank aufzunehmen, und Sie sollten auf jeden Fall Einschränkungen für solche Dinge implementieren, wenn Sie können. Ein Trigger ist jedoch nicht die einzige Alternative. Sie können das Problem im PL / SQL-Paket lösen, das die Einfügung ausführt. Auf diese Weise erhalten Sie weitere Vorteile wie reduzierten clientseitigen Code, weniger Kontextwechsel, automatische Bindungen, Unabhängigkeit von Clientanwendungen usw. Hier ist ein unvollständiges Beispiel (ohne die Sperre, die erforderlich wäre, um dies gleichzeitig auszuführen).
quelle
Ich vermisse eine Tabelle wie CASE_RECOMMENDATION_LIST (CASE_STAGE_ID NUMBER (9) PRIMARY KEY) in Ihrem Design. Jede CASE_RECOMMENDATION ist Mitglied der entsprechenden CASE_RECOMMENDATION_LIST. Dies kann von einem Fremdschlüssel behandelt werden. Eine CASE_RECOMMENDATION_LIST muss mindestens eine CASE_RECOMMENDATION enthalten. Das Erstellen und Löschen einer CASE_RECOMMENDATION_LIST kann durch einfache Trigger erfolgen: Erstellen Sie eine CASE_RECOMMENDATION_LIST für eine CASE_STAGE_ID, bevor die erste CASE_RECOMMENDATION für diese CASE_STAGE_ID erstellt wird. Löschen Sie sie, nachdem die letzte CASE_RECOMMENDATION für diese CASE_STGE_STGE_STGE_ID gelöscht wurde. CASE_STAGE referenziert höchstens eine CASE_RECOMMENDATION_LIST mit der CASE_STAGE.PREVIOUS_CASE_STAGE_ID. CASE_STAGE.PREVOUS_STAGE_ID darf nicht null sein, wenn CASE_STAGE.STAGE_ID = 1646.
Vielleicht wäre es eine bessere Möglichkeit, eine eigene Entität (und damit eine Tabelle) für die 1646 CASE_STAGEs zu erstellen, aber ich werde dies nicht weiter analysieren.
quelle