267 lines
7.7 KiB
Markdown
267 lines
7.7 KiB
Markdown
# 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 | `<zweck>_seq` | `fgt_order_id_seq` |
|
|
| Primary Key (Spalte) | `<tabellenname>_id` | `order_id`, `shipment_id` |
|
|
| Foreign Key (Constraint) | `<beschreibung>_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_<tabellenname>_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: <nur bei funktionen, nicht bei procedures>
|
|
------------------------------------------------------------------------------------------------------
|
|
-- MA Datum Änderung
|
|
-- SCK 2026-04-07 Funktion erstellt
|
|
------------------------------------------------------------------------------------------------Kopf*/
|
|
is
|
|
...
|
|
```
|