# CLAUDE.md — Oracle Database ## Projektbeschreibung Projekt für verschiedene Oracle-Datenbank Entwicklungen. Enthält Tabellendefinitionen, PL/SQL-Packages, ORDS-Endpunkte, Views, Trigger etc. ## SQL / PL/SQL Guidelines ### Formatierung **Keywords immer klein:** ```sql select, from, where, insert into, create table, begin, end, exception, ... ``` **Tab-Ausrichtung in mehrzeiligen Statements:** Schlüsselwort + Tab, dann Inhalt. Erste Spalte und alle nachfolgenden Kommas stehen auf demselben Tab-Stop (eine Fluchtlinie). Komma direkt vor dem Spaltennamen ohne Leerzeichen. ```sql select order_id ,principal_order_number ,total_amount from fgt_order where status = 'COMPLETE' ``` ```sql insert into fgt_order ( order_id ,principal_order_number ,total_amount ) values ( fgt_order_seq.nextval ,p_order_number ,p_total_amount ); ``` **Block-Keywords in eigener Zeile (lineup bracing):** `loop`, `then`, `exception` und ihre schließenden `end`-Varianten stehen auf gleicher Einrückungsebene wie der Block-Öffner: ```sql for rec in cur_open_orders loop l_count := l_count + 1; end loop; if l_count > 0 then do_something(); elsif l_count < 0 then handle_negative(); end if; begin l_result := do_something(); exception when e_not_found then l_result := null; when others then raise; end; ``` **`end`-Anweisungen immer mit Label:** ```sql end my_procedure; end my_package; ``` **Indentation:** 4 Spaces innerhalb von Blöcken. --- ### Benennungskonventionen | Objekt | Konvention | Beispiel | |---|---|---| | Tabellen | Modulabhängiger Präfix, z.B.`adr_`, **Singular**, Dateiendung `.tab` | `sy_parameter`, `adr_adresse_zuweisung`, | | Views | `v_` Präfix | `v_adr_adresse_zuweisung` | | Packages | `pck_` Präfix, Separate header und body Dateien mit den Endungen `.pkh` und `.pkb` | `pck_system` | | Prozeduren | `p_`-Präfix | `p_insert_order`, `p_delete_folder` | | Funktionen | `f_`-Präfix | `f_get_order`, `f_build_url` | | Lokale Variablen | `l_`-Präfix | `l_order_id`, `l_count` | | Parameter (Input) | `i_`-Präfix | `i_json`, `i_order_id` | | Package-globale Variablen | `g_`-Präfix | `g_default_currency` | | Konstanten | `c_`-Präfix | `c_max_retries` | | Cursor | `cur_`-Präfix | `cur_open_orders` | | Exceptions | `e_`-Präfix | `e_not_found`, `e_duplicate` | | Views | `_v`-Suffix | `fgt_order_v` | | Trigger | `trg_`-Präfix | `trg_fgt_order_created_at` | | Sequences | `_seq` | `fgt_order_id_seq` | | Primary Key (Spalte) | `_id` | `order_id`, `shipment_id` | | Foreign Key (Constraint) | `_fk` | `fgt_order_bill_addr_fk` | --- ### PL/SQL-Struktur - `as` für Package-Spec/Body-Header, `is` für Prozedur-/Funktionskörper innerhalb eines Packages - Implizite Cursor-FOR-Loops bevorzugen gegenüber expliziten Cursors - `is null` / `is not null` verwenden — niemals `= null` / `!= null` - Explizite Formatmasken in `to_date`, `to_char`, `to_timestamp` - `commit` nur im äußersten Aufrufer — nie in Sub-Prozeduren ```sql create or replace package body pck_orders as procedure insert_order (i_json in clob, i_run_id in varchar2) is l_order_id number; l_status varchar2(20); begin -- Implementierung l_order_id := bet_order_id_seq.nextval; end insert_order; end fgt_orders; ``` --- ### Exception Handling - **Niemals** `when others then null` — Exceptions nie stillschweigend schlucken - Exceptions mit `e_`-Präfix benennen und im Deklarationsteil definieren - `sqlerrm` und `sqlcode` für Fehlerinformationen nutzen ```sql declare e_invalid_status exception; l_status varchar2(20); begin if l_status not in ('COMPLETE', 'INCOMPLETE') then raise e_invalid_status; end if; exception when e_invalid_status then -- gezielt behandeln log_error('Ungültiger Status: ' || l_status); when others then -- sqlcode / sqlerrm immer loggen, nie schlucken log_error(sqlerrm); raise; end; ``` --- ### Audit-Spalten Jede Tabelle bekommt am Ende vier Audit-Spalten: ```sql create table bet_order ( bet_order_id number generated by default as identity not null enable , ... ,bet_mit_id_angelegt NUMBER(10) not null, ,bet_datum_angelegt DATE not null, ,bet_mit_id_geaendert NUMBER(10) not null, ,bet_datum_geaendert DATE not null, ); ``` Befüllt werden sie über einen `before insert or update`-Trigger pro Tabelle. Namenskonvention: `trg__audit`. ```sql create or replace editionable trigger trg_fgt_order_audit before insert or update on fgt_order referencing new as new old as old for each row declare l_user varchar2(100 byte) := substr(upper(coalesce( sys_context('apex$session', 'app_user'), sys_context('userenv', 'os_user'), sys_context('userenv', 'session_user'))), 1, 100); l_now date := cast(current_timestamp at time zone 'Europe/Berlin' as date); begin if inserting then :new.created_at := l_now; :new.created_by := l_user; end if; :new.changed_at := l_now; :new.changed_by := l_user; end trg_fgt_order_audit; ``` Der Benutzername wird bevorzugt aus der APEX-Session gelesen, mit Fallback auf OS- bzw. DB-Session-User. --- ### Tabellenänderungen (Migrations-Skripte) Tabellen können von SQLcl Projects nicht gedropt und neu erstellt werden, wenn sie Daten enthalten. Änderungen an bestehenden Tabellen werden deshalb als `alter table`-Statements **am Ende der jeweiligen Tabellendatei** ergänzt — nach dem `create table` und dem Primary-Key-Constraint, aber **vor** dem `-- sqlcl_snapshot`-Kommentar. So kann die gesamte Datei als Skript auf eine bestehende Datenbank angewendet werden: Das `create table` schlägt fehl (Tabelle existiert schon), aber die `alter table`-Statements laufen durch und bringen die Tabelle auf den aktuellen Stand. ```sql create table fgt_order ( ... ); alter table fgt_order add constraint pk_fgt_order primary key (order_id) using index enable; -- Migrationsscript — hinzugefügt am 2026-03-30 alter table fgt_order add ( status varchar2(16 char) default 'COMPLETE' not null ,run_id varchar2(36 char) ); -- sqlcl_snapshot { ... } ``` --- ### Planungsdokumente Für komplexere Features/Packages wird ein Planungsdokument als `.md`-Datei im Projektverzeichnis abgelegt (z.B. `plan_pck_net_storage.md`). Der Plan wird während der Umsetzung aktuell gehalten — jede Änderung an Architektur oder Schnittstelle wird sofort im Plan nachgeführt. --- ### Kommentare - Beschreibungen auf **Deutsch**, Code (außer Fachbegriffe der Anwendungsdomäne) auf **Englisch** - Block-Kommentar zu Beginn Prozedur/Funktion mit Zweck und Parametern - Inline-Kommentare mit `--` nur für nicht-offensichtliche Logik ```sql procedure insert_order (i_json in clob, i_run_id in varchar2) /*Kopf------------------------------------------------------------------------------------------------ -- Beschreibung: Fügt einen verarbeiteten Auftrag in die Datenbank ein. ------------------------------------------------------------------------------------------------------ -- Parameter: i_json Klippa-Ergebnis als JSON-String -- i_run_id Ausführungs-Korrelations-ID des Verarbeitungslaufs ------------------------------------------------------------------------------------------------------ -- Rückgabe: ------------------------------------------------------------------------------------------------------ -- MA Datum Änderung -- SCK 2026-04-07 Funktion erstellt ------------------------------------------------------------------------------------------------Kopf*/ is ... ```