-- GWÖ-Wahlprüfsteine Auswertung — Datenbankschema -- Version 1.0, 29.03.2026 -- Kandidat:innen CREATE TABLE IF NOT EXISTS kandidaten ( id INTEGER PRIMARY KEY, vorname TEXT NOT NULL, nachname TEXT NOT NULL, plz TEXT, kommune TEXT NOT NULL, landkreis TEXT, partei_raw TEXT NOT NULL, -- Original aus Umfrage partei_normalisiert TEXT NOT NULL, -- Normalisierte Hauptpartei ist_waehlergemeinschaft BOOLEAN DEFAULT FALSE, pdf_url TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- Die 6 Fragen CREATE TABLE IF NOT EXISTS fragen ( id INTEGER PRIMARY KEY, nummer INTEGER UNIQUE NOT NULL, -- 1-6 kurztext TEXT NOT NULL, -- z.B. "Leitlinien" volltext TEXT NOT NULL -- Vollständige Frage ); -- Rohantworten CREATE TABLE IF NOT EXISTS antworten_raw ( id INTEGER PRIMARY KEY, kandidat_id INTEGER REFERENCES kandidaten(id) ON DELETE CASCADE, frage_id INTEGER REFERENCES fragen(id) ON DELETE CASCADE, antwort_kurz TEXT, -- Ja/Nein/leer antwort_erlaeuterung TEXT, -- Optionale Erläuterung UNIQUE(kandidat_id, frage_id) ); -- LLM-Bewertungen (pro Antwort) CREATE TABLE IF NOT EXISTS bewertungen ( id INTEGER PRIMARY KEY, antwort_id INTEGER REFERENCES antworten_raw(id) ON DELETE CASCADE UNIQUE, -- Substanz: Hat tatsächlich geantwortet? substanz_score INTEGER CHECK(substanz_score >= 0 AND substanz_score <= 3), -- 0 = keine Antwort/nur Ja-Nein -- 1 = ausweichend/oberflächlich -- 2 = substanziell -- 3 = umfassend mit konkreten Maßnahmen -- Umfang umfang TEXT CHECK(umfang IN ('keine', 'kurz', 'mittel', 'ausführlich')), wortanzahl INTEGER, -- GWÖ-Bewertung gwoe_score REAL CHECK(gwoe_score >= 0 AND gwoe_score <= 10), gwoe_begruendung TEXT, -- Matrix-Felder (JSON-Array, z.B. ["D5", "C2"]) matrix_felder TEXT, -- Qualitativ staerken TEXT, schwaechen TEXT, -- Meta bewertet_am DATETIME DEFAULT CURRENT_TIMESTAMP, model TEXT DEFAULT 'qwen-plus' ); -- Partei-Aggregation (View) CREATE VIEW IF NOT EXISTS v_partei_statistik AS SELECT k.partei_normalisiert AS partei, COUNT(DISTINCT k.id) AS anzahl_kandidaten, COUNT(b.id) AS anzahl_antworten, -- Durchschnittswerte ROUND(AVG(b.substanz_score), 2) AS avg_substanz, ROUND(AVG(b.gwoe_score), 2) AS avg_gwoe, ROUND(AVG(b.wortanzahl), 0) AS avg_wortanzahl, -- Verteilung Umfang SUM(CASE WHEN b.umfang = 'keine' THEN 1 ELSE 0 END) AS umfang_keine, SUM(CASE WHEN b.umfang = 'kurz' THEN 1 ELSE 0 END) AS umfang_kurz, SUM(CASE WHEN b.umfang = 'mittel' THEN 1 ELSE 0 END) AS umfang_mittel, SUM(CASE WHEN b.umfang = 'ausführlich' THEN 1 ELSE 0 END) AS umfang_ausfuehrlich FROM kandidaten k LEFT JOIN antworten_raw ar ON k.id = ar.kandidat_id LEFT JOIN bewertungen b ON ar.id = b.antwort_id GROUP BY k.partei_normalisiert; -- Statistik pro Frage CREATE VIEW IF NOT EXISTS v_fragen_statistik AS SELECT f.nummer, f.kurztext, COUNT(b.id) AS anzahl_bewertungen, ROUND(AVG(b.substanz_score), 2) AS avg_substanz, ROUND(AVG(b.gwoe_score), 2) AS avg_gwoe, SUM(CASE WHEN ar.antwort_kurz = 'Ja' THEN 1 ELSE 0 END) AS ja_antworten, SUM(CASE WHEN ar.antwort_kurz = 'Nein' THEN 1 ELSE 0 END) AS nein_antworten FROM fragen f LEFT JOIN antworten_raw ar ON f.id = ar.frage_id LEFT JOIN bewertungen b ON ar.id = b.antwort_id GROUP BY f.id; -- Beste/Schlechteste Antworten CREATE VIEW IF NOT EXISTS v_top_antworten AS SELECT k.vorname || ' ' || k.nachname AS name, k.kommune, k.partei_normalisiert AS partei, f.kurztext AS frage, b.gwoe_score, b.substanz_score, ar.antwort_erlaeuterung AS zitat FROM bewertungen b JOIN antworten_raw ar ON b.antwort_id = ar.id JOIN kandidaten k ON ar.kandidat_id = k.id JOIN fragen f ON ar.frage_id = f.id WHERE b.gwoe_score IS NOT NULL ORDER BY b.gwoe_score DESC; -- Indizes CREATE INDEX IF NOT EXISTS idx_kandidaten_partei ON kandidaten(partei_normalisiert); CREATE INDEX IF NOT EXISTS idx_antworten_kandidat ON antworten_raw(kandidat_id); CREATE INDEX IF NOT EXISTS idx_antworten_frage ON antworten_raw(frage_id); CREATE INDEX IF NOT EXISTS idx_bewertungen_gwoe ON bewertungen(gwoe_score); -- Stammdaten: Fragen INSERT OR IGNORE INTO fragen (nummer, kurztext, volltext) VALUES (1, 'Leitlinien', 'Werden Sie sich für Maßnahmen einsetzen, welche die Werte und Themen der GWÖ in Leitlinien und Strategien Ihrer Kommune/Verwaltung und Eigenbetriebe integrieren?'), (2, 'Anreize', 'Werden Sie sich in Ihrer Kommune für die Schaffung von Anreizen einsetzen, um Unternehmen darin zu unterstützen gemeinwohl-orientierter zu wirtschaften?'), (3, 'Vergabe', 'Werden Sie sich in Ihrer Kommune dafür einsetzen, dass öffentliche Aufträge bevorzugt an Unternehmen vergeben werden, die eine gültige Gemeinwohl-Bilanz vorlegen?'), (4, 'Information', 'Möchten Sie dafür sorgen, dass die Bürger*innen Ihrer Kommune regelmäßig die wichtigsten Informationen zur Entwicklung Ihrer Kommune erhalten – und zwar mit einer Einschätzung inwieweit sie das Gemeinwohl stärken bzw. schwächen?'), (5, 'Mitentscheidung', 'Möchten Sie dafür sorgen, dass die Bürger*innen Ihrer Kommune in kommunale Entscheidungsprozesse fortan stärker eingebunden werden?'), (6, 'Bekanntheit', 'Möchten Sie dafür sorgen, dass die Werte-Orientierung, Themen und Inhalte der GWÖ in Ihrer Kommune und auf höheren politischen Ebenen bekannter werden?');