138 lines
5.5 KiB
MySQL
138 lines
5.5 KiB
MySQL
|
|
-- 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?');
|