Einwilligungsstatus je Ereignis im GA4-BigQuery-Export auslesen

Die Einwilligung taucht in GA4-Berichten als Zusammenfassung auf, wenn überhaupt. Im BigQuery-Export taucht sie je Ereignis auf, in einem verschachtelten Satz neben jeder Zeile, der den Zustand hält, welcher im Augenblick der Aufzeichnung dieses einen Ereignisses galt.
Das ist ein deutlich besserer Gegenstand zum Arbeiten, und er bringt eine Falle mit, die eine falsche Zahl erzeugt statt eines Fehlers.

Wo er steht
Der Satz heißt privacy_info und hält die Speicherzustände als Zeichenketten, nicht als Wahrheitswerte. Weil er verschachtelt ist, braucht er Punktzugriff; weil es Zeichenketten sind, braucht er Vergleiche in Anführungszeichen; und weil sie leer sein können, braucht er vor jeder Quote eine Entscheidung darüber, was ein fehlender Wert bedeutet.
SELECT
event_date,
privacy_info.analytics_storage AS analytics,
privacy_info.ads_storage AS ads,
COUNT(*) AS ereignisse
FROM `projekt.analytics_XXXXXX.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20260801' AND '20260831'
GROUP BY 1, 2, 3
ORDER BY 1, 4 DESC
-- vor jedem Filter laufen lassen. Der Zweck ist zu sehen,
-- wie viele Zeilen in den dritten Topf fallen, denn diese
-- Zahl entscheidet, ob die Falle unten ueberhaupt greift
Erst gruppieren und dann filtern ist hier die ganze Disziplin. Das kostet eine Abfrage, auf einem einzelnen Monat fast nichts, und beantwortet die Frage, von der jede weitere Abfrage abhängt.
Die Falle
Zwei Filter, die sich wie Gegensätze lesen, sind keine. analytics_storage = 'No' wählt Ereignisse mit ausdrücklicher Ablehnung. analytics_storage != 'Yes' wählt Ablehnungen plus alles ohne festgehaltenen Zustand – denn in SQL ergibt ein Vergleich gegen einen Leerwert wieder einen Leerwert und nicht wahr, sodass der erste Filter die leeren Zeilen still fallen lässt und der zweite sie behält.
Eine Einwilligungsquote auf dem ersten fällt höher aus als eine auf dem zweiten, auf denselben Daten, für denselben Tag. Von außen ist keine der beiden offensichtlich falsch; beide liefern einen plausiblen Prozentsatz. Welche stimmt, hängt davon ab, was die Leerwerte tatsächlich sind, und das ist eine Frage an die Umsetzung, nicht an SQL.
Leerwerte bedeuten meistens, dass beim Auslösen des Ereignisses kein Einwilligungssignal beim Tag ankam – ein Treffer vor der Entscheidung am Banner, eine Seite, auf der die Einwilligungsplattform nicht lud, ein serverseitiges Ereignis, das ohne durchgereichten Zustand gebaut wurde. Das sind drei verschiedene Lagen mit drei verschiedenen Bedeutungen, und sie mit ausdrücklichen Ablehnungen in einen Topf zu werfen, überzeichnet die Ablehnung.
Was damit möglich wird
Weil der Zustand je Ereignis und nicht je Bestand vorliegt, lässt er sich mit allem anderen auf der Zeile kreuzen.
nach Seite welche Seiten am haeufigsten abgelehnt werden
meist die, auf denen das Banner mit dem Inhalt
um dieselbe Bildschirmflaeche ringt
nach Geraet Mobil und Rechner unterscheiden sich weit
genug, dass eine Gesamtzahl keines von beiden
beschreibt
nach Quelle Verkehr aus einem Link innerhalb einer App
verhaelt sich anders als ein Direktbesuch
nach Stunde eine Auslieferung, die das Banner zerlegt,
zeigt sich als Stufe zu einer bestimmten
Stunde - was ein Tageswert vollstaendig
glaettet
Der Schnitt nach Seite lohnt sich am schnellsten, weil er aus einer Zahl, mit der niemand etwas anfangen kann, eine Liste konkreter Seiten macht.
Zwei Dinge, die über die Zeile zu wissen sind
Ein einzelner Besuch kann Ereignisse in mehr als einem Zustand enthalten. Wer ein Banner mitten in einer Sitzung annimmt, hinterlässt unter derselben Pseudokennung eine Spur abgelehnter Ereignisse, gefolgt von erteilten – was richtig ist und jede Abfrage leise zerlegt, die einen Zustand je Nutzer annimmt.
Und das Exportschema wächst. Der Ereignistabelle wurden schon Felder hinzugefügt und werden wieder welche hinzugefügt, was das Argument gegen SELECT * in allem Nachgelagerten ist: Eine unangekündigt eintreffende Spalte ist harmlos für eine Abfrage, die ihre Spalten benennt, und ein gebrochener Ladeauftrag für eine, die es nicht tut.