Odczyt statusu zgody dla pojedynczego zdarzenia w eksporcie GA4 do BigQuery

Zgoda pojawia się w raportach GA4 jako zestawienie, jeśli w ogóle. W eksporcie do BigQuery pojawia się przy każdym zdarzeniu, w zagnieżdżonym rekordzie zapisanym obok każdego wiersza, trzymającym stan obowiązujący w chwili zapisu tego jednego zdarzenia.
To znacznie lepszy przedmiot do pracy i niesie ze sobą jedną pułapkę tworzącą błędną liczbę zamiast błędu.

Gdzie stoi
Rekord nazywa się privacy_info i trzyma stany przechowywania jako ciągi znaków, nie jako wartości logiczne. Ponieważ jest zagnieżdżony, wymaga dostępu przez kropkę; ponieważ to ciągi, wymaga porównań w cudzysłowie; a ponieważ mogą być puste, wymaga przed każdym współczynnikiem rozstrzygnięcia, co oznacza brak wartości.
SELECT
event_date,
privacy_info.analytics_storage AS analytics,
privacy_info.ads_storage AS ads,
COUNT(*) AS zdarzenia
FROM `projekt.analytics_XXXXXX.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20260801' AND '20260831'
GROUP BY 1, 2, 3
ORDER BY 1, 4 DESC
-- do uruchomienia przed kazdym filtrem. Chodzi o to, by
-- zobaczyc, ile wierszy wpada do trzeciego kubelka, bo ta
-- liczba rozstrzyga, czy pulapka nizej w ogole dziala
Najpierw grupowanie, potem filtr – na tym polega tu cała dyscyplina. Kosztuje jedno zapytanie, na pojedynczym miesiącu prawie nic, i odpowiada na pytanie, od którego zależy każde kolejne.
Pułapka
Dwa filtry czytające się jak przeciwieństwa nie są przeciwieństwami. analytics_storage = 'No' wybiera zdarzenia z wyraźną odmową. analytics_storage != 'Yes' wybiera odmowy plus wszystko bez utrwalonego stanu – bo w SQL porównanie z wartością pustą daje znowu wartość pustą, a nie prawdę, więc pierwszy filtr po cichu gubi puste wiersze, a drugi je zachowuje.
Współczynnik zgody na pierwszym wypada wyżej niż na drugim, na tych samych danych, dla tego samego dnia. Z zewnątrz żaden nie jest oczywiście błędny; oba dają wiarygodny procent. Który jest prawdziwy, zależy od tego, czym naprawdę są wartości puste, a to pytanie do wdrożenia, nie do SQL.
Wartości puste zwykle znaczą, że przy odpaleniu zdarzenia do tagu nie dotarł żaden sygnał zgody – trafienie przed rozstrzygnięciem na banerze, strona, na której platforma zgód się nie wczytała, zdarzenie po stronie serwera zbudowane bez przekazanego stanu. To trzy różne sytuacje o trzech różnych znaczeniach, a wrzucanie ich do jednego worka z wyraźnymi odmowami zawyża odmowę.
Co staje się dzięki temu możliwe
Ponieważ stan jest przy zdarzeniu, a nie przy zasobie, da się go skrzyżować ze wszystkim innym w wierszu.
wedlug strony ktore strony sa odrzucane najczesciej
zwykle te, na ktorych baner walczy z trescia
o te sama powierzchnie ekranu
wedlug urzadzenia komorka i komputer roznia sie na tyle, ze
liczba ogolna nie opisuje zadnego z nich
wedlug zrodla ruch z linku wewnatrz aplikacji zachowuje
sie inaczej niz wizyta bezposrednia
wedlug godziny wdrozenie psujace baner pokazuje sie jako
stopien o okreslonej godzinie - co wartosc
dzienna calkowicie wygladza
Przekrój według strony zwraca się najszybciej, bo zamienia liczbę, z którą nikt nic nie zrobi, w listę konkretnych stron.
Dwie rzeczy warte wiedzenia o wierszu
Pojedyncza wizyta może zawierać zdarzenia w więcej niż jednym stanie. Kto przyjmuje baner w połowie sesji, zostawia pod tym samym identyfikatorem pseudonimowym ślad zdarzeń odmówionych, po których idą udzielone – co jest poprawne i po cichu psuje każde zapytanie zakładające jeden stan na użytkownika.
A schemat eksportu rośnie. Do tabeli zdarzeń dodawano już pola i dodane zostaną kolejne, co jest argumentem przeciwko SELECT * we wszystkim dalej: kolumna przychodząca bez zapowiedzi jest nieszkodliwa dla zapytania wymieniającego kolumny z nazwy i zerwanym zadaniem ładowania dla takiego, które ich nie nazywa.