====== 3.3 ENIVERSPIMS — Sicherheitsgespräche ====== //Stand: 2026-03-05// Übergeordnet: [[de:int:wvdsshell:notes:03-pims:start|PIMS-Architektur — Gesamtübersicht]] Verwandt: [[de:int:wvdsshell:notes:03-pims:inspection|3.1 Prüfwesen]] | [[de:int:wvdsshell:notes:03-pims:work-orders|3.2 Arbeitsaufträge]] ===== Ausgangslage: Zwei parallele Systeme ===== Sicherheitsgespräche / SIL-Bewertungen werden in **zwei getrennten** Legacy-Systemen geführt: ^ Merkmal ^ AMED EZASichGesp ^ ENIVERS tblSicherheitGespraech ^ | Datensätze | 5.862 Zeilen | 60 Zeilen | | Spaltenanzahl | 73 | 59 | | Primärschlüssel | IDEZA (FK → EZAMASTER) | idSicherheitGespraech | | Verknüpfung | pro EZA-Objekt (Instrument/Sensor) | pro Anlage/Schutzziel (fiSigBetrieb) | | Risikodimensionen | SCHADENAUSMASS, AUFENTHALTSDAUER, GEFAHRENABWEICHUNG, EINTRITTSWAHRSCHEINL | intSigAusmassSchaden, intSigAufenthaltGefahrBereich, intSigVermeidungGefahr, intSigEintrittWahrscheinlichkeit | | SIL-Feld | SIL (tinyint) | strSbWertSIL (via tblSicherheitBaum) | | Klassifizierung | Klassif_A/B/C/X (bits), Risikoklasse | strSbKennbuchstaben, Klassifizierung, Status | | Rechtl. Anforderungen | 10 bit-Flags (Dampfk_V, VAWS, VBF, ...) | bln*-Felder | | Aktor/Sensor-Daten | 8×(Schalt_Klassi, Kontakt, Grenzwert) — denormalisiert | tblSicherheitGespraechAktorSensor (normalisiert) | | Unterschriften | — (nicht vorhanden) | tblSicherheitUnterschrift | | Alarmschwellen | — (nicht vorhanden) | strSigMinVoralarm ... strSigMaxAbschaltung2 | | Schutzziel-Freitext | — (nicht vorhanden) | memSigSchutzziel (nvarchar MAX) | ==== Kernunterschiede ==== * **AMED EZASichGesp** = Sicherheitsgespräch pro **EZA-Instrument/Aktor** (Mikroebene). Fokus: Klassifikation (A/B/C/X), gesetzliche Anforderungen, Risikoklasse, SIL-Ergebnis. * **ENIVERS tblSicherheitGespraech** = SIL-Bewertung pro **Schutzziel** (Makroebene). Fokus: Schutzziel-Freitext, Alarmschwellen, strukturierte AktorSensor-Liste, Unterschriften. Beide basieren auf derselben **4-dimensionalen Risikomatrix** (Schadensausmaß × Aufenthaltsdauer × Vermeidbarkeit × Eintrittswahrscheinlichkeit → SIL). ===== Merge-Strategie: "Must Have" ohne Datenverlust ===== ==== Prinzip: gemeinsame Tabelle + conversation_type-Unterscheidung ==== Ein Merge ist möglich, weil der **strukturelle Kern identisch** ist. Quell-spezifische Felder werden erhalten — entweder als echte Spalten oder als JSON. AMED EZASichGesp ──► safety.conversation (type='EZA') │ conversation_actor_sensor (aus 8×denorm. Spalten normalisiert) ENIVERS tblSgEspr ──► safety.conversation (type='SCHUTZZIEL') │ conversation_actor_sensor (aus tblSicherheitGespraechAktorSensor) │ conversation_justification (aus tblSicherheitGespraechBegruendung) │ conversation_signature (aus tblSicherheitUnterschrift) ==== Migration ohne Datenverlust ==== * Alle ''legacy_id'' + ''legacy_source'' bleiben erhalten → bidirektionale Traceability * Denormalisierte Spalten (EZASichGesp.Schalt_Klassi1–8 × 3 = 24 Spalten) → normalisiert in ''conversation_actor_sensor'' (max. 8 Zeilen pro Gespräch) * Quell-spezifische Felder ohne Entsprechung auf der anderen Seite → ''extended_data NVARCHAR(MAX)'' als JSON ===== safety.conversation ===== CREATE TABLE safety.conversation ( id INT NOT NULL IDENTITY PRIMARY KEY, conversation_type VARCHAR(20) NOT NULL, -- 'EZA' | 'SCHUTZZIEL' -- Verknüpfung item_id INT NULL, -- FK → ENIVERSCAFM.asset.item (für EZA) branch_id INT NULL, -- FK → ENIVERSCAFM.org.branch (für SCHUTZZIEL) -- Identifikation bau_nummer NVARCHAR(20) NULL, -- Bau-/RI-Nummer ri_fliessbild_nr NVARCHAR(20) NULL, -- R&I-Fließbild Nummer (tblSgEspr: strSigRiFliessbild) blatt_nummer INT NULL, -- Blattnummer anlage_teil NVARCHAR(50) NULL, bezeichnung NVARCHAR(200) NULL, schutzziel NVARCHAR(MAX) NULL, -- Schutzziel-Freitext (nur tblSgEspr) -- Risikomatrix (beide Systeme, 4 Dimensionen) risk_damage SMALLINT NULL, -- Schadensausmaß risk_presence SMALLINT NULL, -- Aufenthaltsdauer risk_avoidance SMALLINT NULL, -- Gefahrenvermeidung/-abweichung risk_probability SMALLINT NULL, -- Eintrittswahrscheinlichkeit -- Ergebnis sil_required TINYINT NULL, -- geforderter SIL (aus Risikomatrix) sil_achieved TINYINT NULL, -- erreichter SIL (aus MSR-Maßnahmen) risk_class NVARCHAR(5) NULL, -- Risikoklasse classification NVARCHAR(5) NULL, -- A / B / C / X -- Klassif.-bits (EZA): als JSON gespeichert klassif_a BIT NULL, klassif_b BIT NULL, klassif_c BIT NULL, klassif_x BIT NULL, -- Gesetzliche Anforderungen (EZA: 10 bit-Flags → JSON) legal_flags NVARCHAR(MAX) NULL, -- Technische Ausführung MSR techn_msr_notes NVARCHAR(MAX) NULL, -- Alarmschwellen (tblSgEspr: 4 Werte → JSON) alarm_thresholds NVARCHAR(MAX) NULL, -- Funktionsbeschreibung (EZASichGesp.Funktion) function_desc NVARCHAR(MAX) NULL, -- Abschluss done_at DATETIME2 NULL, -- Erweiterungs-JSON (quell-spezifische Felder ohne allg. Entsprechung) extended_data NVARCHAR(MAX) NULL, -- Migration legacy_id INT NULL, legacy_source VARCHAR(20) NULL, -- 'AMED_EZA' | 'ENIVERS_LD' -- Audit created_at DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME(), updated_at DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME(), created_by INT NULL, updated_by INT NULL ) ===== safety.conversation_actor_sensor ===== Normalisiert die denormalisierten EZASichGesp-Spalten (Schalt_Klassi1–8, Kontakt1–8, Grenzwert1–8) **und** tblSicherheitGespraechAktorSensor in eine gemeinsame Tabelle: CREATE TABLE safety.conversation_actor_sensor ( id INT NOT NULL IDENTITY PRIMARY KEY, conversation_id INT NOT NULL, -- FK → safety.conversation sort_order SMALLINT NOT NULL DEFAULT 0, -- Identifikation plt_stelle NVARCHAR(100) NULL, -- PLT-Stelle / Funktionsbezeichnung typ NVARCHAR(50) NULL, -- Aktor- oder Sensortyp nummer NVARCHAR(50) NULL, -- Geräte-/KKS-Nummer -- Aktor-Wirkung (aus tblSgEspr) aktor_wirkung NVARCHAR(100) NULL, aktor_stellung NVARCHAR(100) NULL, -- Sensor-Messbereich (aus tblSgEspr) messbereich_von DECIMAL(10,4) NULL, messbereich_bis DECIMAL(10,4) NULL, einheit NVARCHAR(20) NULL, -- Klassifizierung (aus EZASichGesp Schalt_Klassi1–8) klassifizierung NVARCHAR(10) NULL, kontakt NVARCHAR(10) NULL, grenzwert NVARCHAR(20) NULL, grenzwert_einheit NVARCHAR(10) NULL, -- Belegung (aus tblSgEspr.fiSgasBelegung) belegung_id INT NULL, -- Sonstiges zusatz_info NVARCHAR(500) NULL ) ===== safety.conversation_signature ===== CREATE TABLE safety.conversation_signature ( id INT NOT NULL IDENTITY PRIMARY KEY, conversation_id INT NOT NULL, -- FK → safety.conversation sort_order INT NOT NULL, name NVARCHAR(150) NULL, title NVARCHAR(150) NULL, signed_at DATETIME2 NULL ) ===== safety.conversation_justification ===== Begründungsstruktur aus ''tblSicherheitGespraechBegruendung'' (SIL-Stufenbegründung): CREATE TABLE safety.conversation_justification ( id INT NOT NULL IDENTITY PRIMARY KEY, conversation_id INT NOT NULL, -- FK → safety.conversation level_code VARCHAR(5) NULL, -- Stufe (intSbStufe / strSbText) text NVARCHAR(1024) NULL ) ===== tblSicherheitBaum — Risikomatrix-Lookup ===== Die LD-Tabelle ''tblSicherheitBaum'' ist ein Lookup für die 4-dimensionale Risikomatrix (Schadensausmaß × Aufenthaltsdauer × Vermeidbarkeit × Eintrittswahrscheinlichkeit → SIL-Wert). Sie wird als **seed data** in ''shared.list_item'' oder als separate kleine Tabelle migriert: CREATE TABLE safety.risk_matrix ( id INT NOT NULL IDENTITY PRIMARY KEY, damage_code VARCHAR(5) NOT NULL, presence_code VARCHAR(5) NULL, avoidance_code VARCHAR(5) NULL, probability_code VARCHAR(5) NOT NULL, sil_label VARCHAR(10) NULL, -- 'SIL 1', 'SIL 2', 'SIL 3', 'k' ak_label VARCHAR(10) NULL, -- Anforderungsklasse UNIQUE (damage_code, presence_code, avoidance_code, probability_code) ) -- Migration: alle Zeilen aus tblSicherheitBaum ===== Migrations-SQL-Skizze ===== -- 1. AMED EZASichGesp → safety.conversation (type='EZA') INSERT INTO safety.conversation ( conversation_type, item_id, risk_damage, risk_presence, risk_avoidance, risk_probability, sil_required, risk_class, klassif_a, klassif_b, klassif_c, klassif_x, techn_msr_notes, function_desc, done_at, legal_flags, legacy_id, legacy_source, created_at, updated_at ) SELECT 'EZA', i.id, -- asset.item.id via IDEZA → EZAMASTER → APPMASTER → asset.item (legacy_id) e.Schadenausmass_kurz, e.Aufenthaltsdauer_kurz, e.Gefahrenabweichung_kurz, e.Eintrittswahrscheinlichkeit_kurz, e.SIL, e.Risikoklasse, e.Klassif_A, e.Klassif_B, e.Klassif_C, e.Klassif_X, e.TECHN_AUSFUHR_MSR, e.Funktion, e.Done, -- legal_flags als JSON aus den 10 bit-Spalten: (SELECT e.Dampfk_V AS dampfk_v, e.VAWS AS vaws, e.VBF AS vbf, e.Gasbrenner AS gasbrenner, e.Stoerf_V AS stoerf_v, e.Einleitb AS einleitb, e.UVV_VBG AS uvv_vbg, e.Druckb_V AS druckb_v, e.Genehmigungsb AS genehmigungsb, e.Sonst_V AS sonst_v FOR JSON PATH, WITHOUT_ARRAY_WRAPPER), e.IDEZA, 'AMED_EZA', e.dtmEsgCreated, e.dtmEsgUpdated FROM [AMED].[dbo].[EZASichGesp] e LEFT JOIN ENIVERSCAFM.asset.item i ON i.legacy_id = CAST( -- IDEZA → EZAMASTER.erwAppNr → asset.item.legacy_id (SELECT CAST(m.erwAppNr AS VARCHAR) FROM [AMED].[dbo].[EZAMASTER] m WHERE m.IDEZA = e.IDEZA) AS VARCHAR) AND i.legacy_source = 'AMED'; -- 2. Denormalisierte Aktor-Spalten in conversation_actor_sensor auffalten -- (Schalt_Klassi1..8 × Kontakt1..8 × Grenzwert1..8 → 8 Zeilen pro Gespräch) INSERT INTO safety.conversation_actor_sensor (conversation_id, sort_order, klassifizierung, kontakt, grenzwert, grenzwert_einheit) SELECT c.id, v.ord, v.klassi, v.kont, v.grenz, v.grenzeinh FROM safety.conversation c JOIN [AMED].[dbo].[EZASichGesp] e ON e.IDEZA = c.legacy_id AND c.legacy_source = 'AMED_EZA' CROSS APPLY (VALUES (1, e.Schalt_Klassi1, e.Kontakt1, e.Grenzwert1, e.Grenzwerteinh1), (2, e.Schalt_Klassi2, e.Kontakt2, e.Grenzwert2, e.Grenzwerteinh2), -- ... bis 8 (8, e.Schalt_Klassi8, e.Kontakt8, e.Grenzwert8, e.Grenzwerteinh8) ) AS v(ord, klassi, kont, grenz, grenzeinh) WHERE COALESCE(v.klassi, v.kont, v.grenz) IS NOT NULL;