Reguläre Ausdrücke (Regex) in SQL

Reguläre Ausdrücke (Regular Expressions) sind eine besondere Art von Zeichenketten, die in der Programmierung verwendet werden, um bestimmte Muster in Texten zu suchen und zu manipulieren. Reguläre Ausdrücke bestehen aus einer Kombination aus normalen Zeichen und speziellen Zeichen, die als Metazeichen bezeichnet werden. Mit diesen Metazeichen kann man komplexe Muster definieren, wie z.B. eine E-Mail-Adresse oder eine Telefonnummer. Reguläre Ausdrücke können in vielen Programmiersprachen, einschließlich SQL, verwendet werden.

-> Zu den Techniken

Verwendungszwecke von regulären Ausdrücken:

  • Überprüfung von Eingabewerten: Reguläre Ausdrücke können verwendet werden, um sicherzustellen, dass bestimmte Arten von Eingaben, wie E-Mail-Adressen oder Telefonnummern, einem bestimmten Muster entsprechen.
  • Textsuche und -ersetzung: Reguläre Ausdrücke können verwendet werden, um bestimmte Teile eines Texts zu suchen und zu ersetzen.
  • Textanalyse: Reguläre Ausdrücke können verwendet werden, um Daten aus unstrukturierten Texten zu extrahieren und zu analysieren.

Vorteile von regulären Ausdrücken:

  • Zeitersparnis: Reguläre Ausdrücke ermöglichen es, komplexe Textaufgaben in kurzer Zeit zu erledigen.
  • Genauigkeit: Reguläre Ausdrücke bieten eine präzise Möglichkeit, bestimmte Muster im Text zu identifizieren.
  • Portabilität: Reguläre Ausdrücke werden in vielen Programmiersprachen unterstützt, was sie zu einem universellen Werkzeug für Textaufgaben macht.
  • Flexibilität: Reguläre Ausdrücke können leicht an neue Anforderungen angepasst werden, um unterschiedliche Textmuster zu erfassen.

Hier sind einige Beispiele für die Verwendung von regulären Ausdrücken (RegEx):

  1. Überprüfung der Gültigkeit einer E-Mail-Adresse: Eine RegEx wie /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ kann verwendet werden, um sicherzustellen, dass eine eingegebene E-Mail-Adresse einen gültigen Aufbau hat.
  2. Extrahieren von Informationen aus Text: RegEx wie /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/ kann verwendet werden, um Telefonnummern aus Text zu extrahieren.
  3. Überprüfung der Gültigkeit eines Passworts: Eine RegEx wie /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/ kann verwendet werden, um sicherzustellen, dass ein Passwort mindestens 8 Zeichen lang ist und sowohl Buchstaben als auch Zahlen enthält.
  4. Ersetzen von Text: RegEx wie /Microsoft/g kann verwendet werden, um alle Vorkommen des Wortes “Microsoft” in einem Textdokument zu ersetzen.
  5. Validierung von Formulareingaben: RegEx wie /^\d{5}(?:[-\s]\d{4})?$/ kann verwendet werden, um sicherzustellen, dass ein Formularfeld eine gültige Postleitzahl enthält.

Regex Techniken

  1. Einfaches Zeichen-Matching: Ein einfaches Beispiel wäre, ein einzelnes Alphabetzeichen in einem Text zu suchen. RegEx: /a/. Es sucht nach einem einzelnen “a”.
  2. Mehrzeichen-Matching: Um nach einer Zeichenfolge zu suchen, kann man die Zeichen einfach hintereinander schreiben. RegEx: /hello/. Es sucht nach dem Wort “hello”.
  3. Wildcard-Matching: Ein Punkt (.) kann verwendet werden, um ein beliebiges Zeichen zu repräsentieren. RegEx: /.ello/. Es sucht nach Wörtern, die mit einem beliebigen Buchstaben und dem Wort “ello” enden.
  4. Quantifikatoren: Quantifikatoren ermöglichen es, das Vorkommen von Zeichen zu definieren. Zum Beispiel {3} bedeutet, dass das vorhergehende Zeichen 3 Mal vorkommen muss. RegEx: /\d{3}/. Es sucht nach Zahlen mit genau 3 Ziffern.
  5. Gruppierungen und Alternativen: Um nach mehreren Möglichkeiten zu suchen, kann man Gruppierungen und Alternativen verwenden. Zum Beispiel: RegEx /(red|green|blue)/. Es sucht nach den Wörtern “red”, “green” oder “blue”.
  6. Start- und End-of-Line: Der Caret (^) repräsentiert den Anfang einer Zeile und das Dollarzeichen ($) repräsentiert das Ende einer Zeile. RegEx: /^hello$/. Es sucht nach einer Zeile, die genau das Wort “hello” enthält.
  7. Zeichenklassen: Zeichenklassen ermöglichen es, eine Gruppe von Zeichen auf einmal zu suchen. Zum Beispiel [0-9] sucht nach einer Ziffer. RegEx: /[a-zA-Z]{3}/. Es sucht nach einem Wort mit genau 3 Buchstaben.
  8. Vor- und Nachbedingungen: Vor- und Nachbedingungen ermöglichen es, die Reihenfolge der Zeichen zu bestimmen. Zum Beispiel (?=\d) bedeutet, dass eine Ziffer im Anschluss an das vorhergehende Zeichen stehen muss. RegEx: `/hello(?=\sworld)/. Es sucht nach dem Wort “hello”, gefolgt von einem Leerzeichen und dem Wort “
  9. Negierte Zeichenklassen: Mit einem Schlüsselzeichen ^ innerhalb einer Zeichenklasse kann man angeben, dass bestimmte Zeichen nicht vorkommen dürfen. RegEx: /[^0-9]/. Es sucht nach Zeichen, die keine Ziffern sind.
  10. Referenzen auf bereits gefundene Gruppen: Es ist möglich, auf bereits gefundene Gruppen zu verweisen, um weitere Suchmuster zu definieren. RegEx: /(\d)\1/. Es sucht nach einer doppelten Ziffer, indem es auf die erste gefundene Ziffer referenziert.
  11. Lookahead- und Lookbehind-Assertions: Lookahead- und Lookbehind-Assertions ermöglichen es, Vor- und Nachbedingungen zu definieren, ohne dass das Zeichen selbst Teil des gefundenen Musters ist. RegEx: /(?<=\d)\w+(?=\s)/. Es sucht nach einem Wort, das von einer Ziffer und einem Leerzeichen eingeschlossen ist.
  12. Alternation: Mit Alternation kann man mehrere Möglichkeiten für ein Muster angeben. RegEx: /Mr\.|Ms\.|Dr\./. Es sucht nach den Abkürzungen für “Mr.”, “Ms.” oder “Dr.”.
  13. Unicode-Unterstützung: RegEx kann auch mit Unicode-Zeichen arbeiten, um Text aus verschiedenen Sprachen zu verarbeiten. RegEx: /^\p{L}+$/u. Es sucht nach einer Zeichenfolge, die nur aus Buchstaben besteht.
  14. Modifikatoren: Mit Modifikatoren kann man bestimmte Optionen für ein Muster angeben, wie z.B. “Case Insensitive” oder “Multi-Line”. RegEx: /^(?i)ignorecase$/. Es sucht nach dem Text “ignorecase”, unabhängig davon, ob die Buchstaben groß- oder kleingeschrieben sind.
  15. Recursion: Mit Recursion kann man RegEx-Muster verwenden, um sich selbst zu referenzieren. RegEx: /^(.*?)\1$/. Es sucht nach einer Zeichenfolge, die sich selbst wiederholt.
  16. Subroutines: Subroutines ermöglichen es, ein Muster mehrfach innerhalb einer RegEx zu verwenden. RegEx: /(\d\d)\d?\1/. Es sucht nach einer Zahl, die eine doppelte Ziffer enthält.
  17. Anchors: Anchors sind spezielle Zeichen, die das Matching an bestimmten Stellen des Texts festlegen. RegEx: /^\d+$/. Es sucht nach einer Zeichenfolge, die nur aus Ziffern besteht und am Anfang und Ende des Texts ankerst.
  18. Greedy und Lazy Quantifiers: Greedy und Lazy Quantifiers legen fest, wie weit ein Muster matcht. RegEx: /^.*?word.*?$/. Es sucht nach einem Text, der das Wort “word” enthält, aber das geringstmögliche Match ausführt.
  19. Named Capturing Groups: Named Capturing Groups ermöglichen es, benannte Gruppen innerhalb einer RegEx zu erstellen und zu referenzieren. RegEx: /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/. Es sucht nach einem Datum im Format “JJJJ-MM-TT”.
  20. Atomic Groups: Atomic Groups ermöglichen es, dass eine RegEx als eine einzige Einheit betrachtet wird, wodurch das Backtracking verhindert wird. RegEx: /^(?>.*?word.*?)$/. Es sucht nach einem Text, der das Wort “word” enthält, aber Backtracking verhindert.
  21. Lookaround: Lookaround ermöglichen es, dass bestimmte Bedingungen erfüllt sein müssen, ohne dass die Bedingungen Teil des Matches sind. RegEx: /(?<=prefix)word(?=suffix)/. Es sucht nach dem Wort “word”, aber nur dann, wenn es von dem Präfix “prefix” gefolgt und vom Suffix “suffix” vorangestellt wird.

ETL vs. ELT: was ist der Unterschied?

Bei der Betrachtung von ETL- und ELT-Prozessen ist es wichtig, die Hauptunterschiede und die spezifischen Anwendungsfälle für zu berücksichtigen.

ETL (Extrahieren, Transformieren, Laden) und ELT (Extrahieren, Laden, Transformieren) sind beides Datenintegrationsmethoden, die Daten von einer Quelle in ein Data Warehouse übertragen. Trotz ihrer Ähnlichkeiten unterscheiden sich ETL und ELT in wesentlichen Punkten.

ETL- Prozess – Überblick

Extrahieren, Transformieren und Laden (ETL) ist eine Methode der Datenintegration, bei der Rohdaten aus Quellen extrahiert, auf einem sekundären Verarbeitungsserver transformiert und dann in eine Zieldatenbank geladen werden.

ETL wird eingesetzt, wenn Daten so umgewandelt werden müssen, dass sie mit dem Datenregime einer Zieldatenbank übereinstimmen. Diese Methode ist vor allem bei der Nutzung von eigenen Servern mit begrenztem Speicher und begrenzter Verarbeitungsleistung weit verbreitet.

Online Analytical Processing (OLAP) Data Warehouses akzeptieren nur relationale SQL-basierte Datenstrukturen.

Bei dieser Art von Data Warehouse stellt ein Protokoll mit ETL-Prozess die Konformität sicher, indem es die extrahierten Daten an einen Verarbeitungsserver weiterleitet und dann die nicht konformen Daten in SQL-basierte Daten umwandelt.

Die extrahierten Daten gelangen erst dann vom Verarbeitungsserver in das Data Warehouse, wenn sie erfolgreich umgewandelt wurden.

ELT-Prozess – Überblick

Im Gegensatz zu ETL-Prozessen müssen beim Extrahieren, Laden und Transformieren (ELT) vor dem Ladevorgang keine Datenumwandlungen vorgenommen werden.

ELT lädt Rohdaten direkt in ein Ziel-Data-Warehouse, anstatt sie zur Transformation auf einen Verarbeitungsserver zu verschieben.

Mit ELT finden Datenbereinigung, -anreicherung und -umwandlung innerhalb des Data Warehouse selbst statt. Die Rohdaten werden auf unbestimmte Zeit im Data Warehouse gespeichert, so dass sie mehrfach umgewandelt werden können.

ELT ist eine relativ neue Entwicklung, die durch die Erfindung skalierbarer Cloud-basierter Data Warehouses ermöglicht wurde.

Cloud-Data-Warehouses wie Snowflake, Amazon Redshift, Google BigQuery und Microsoft Azure verfügen alle über die digitale Infrastruktur in Bezug auf Speicher- und Verarbeitungsleistung, um Rohdaten-Repositories und In-App-Transformationen zu erleichtern.

Obwohl ELT nicht universell eingesetzt wird, wird die Methode immer beliebter.

ETL vs. ELT: Wie unterscheidet sich der ETL-Prozess vom ELT-Prozess?

ETL und ELT unterscheiden sich vor allem in zwei Punkten. Ein Unterschied besteht darin, wo die Daten umgewandelt werden, und der andere darin, wie Data Warehouses die Daten aufbewahren.

  • ETL wandelt Daten auf einem separaten Verarbeitungsserver um, während ELT Daten innerhalb des Data Warehouse selbst umwandelt.
  • ETL überträgt keine Rohdaten in das Data Warehouse, während ELT Rohdaten direkt an das Data Warehouse sendet.

Bei ETL wird der Prozess der Datenaufnahme dadurch verlangsamt, dass die Daten vor dem Ladevorgang auf einem separaten Server transformiert werden.

ELT hingegen ermöglicht eine schnellere Datenaufnahme, da die Daten nicht zur Umstrukturierung an einen zweiten Server geschickt werden. Mit ELT können die Daten sogar gleichzeitig geladen und umgewandelt werden.

Die Rohdatenaufbewahrung von ELT schafft ein umfangreiches historisches Archiv für die Erstellung von Business Intelligence. Wenn sich Ziele und Strategien ändern, können BI-Teams die Rohdaten erneut abrufen, um neue Transformationen unter Verwendung umfassender Datensätze zu entwickeln. ETL hingegen erzeugt keine vollständigen Rohdatensätze, die endlos abgefragt werden können.

Diese Faktoren machen ELT flexibler, effizienter und skalierbarer, insbesondere für die Aufnahme großer Datenmengen, die Verarbeitung von Datensätzen, die sowohl strukturierte als auch unstrukturierte Daten enthalten, und die Entwicklung vielfältiger Business Intelligence.

Auf der anderen Seite ist ETL ideal für rechenintensive Transformationen, Systeme mit Legacy-Architekturen oder Daten-Workflows, die vor der Eingabe in ein Zielsystem manipuliert werden müssen, wie z. B. die Löschung von personenbezogenen Daten.

Warum wird ETL häufig in traditionellen Data Warehouse-Umgebungen verwendet, während ELT in Big Data-Umgebungen beliebter ist?

ETL wird häufig in traditionellen Data Warehouse-Umgebungen verwendet, da die Transformationen in diesen Umgebungen oft aufwendig und rechenintensiv sind. Diese Transformationen werden in der Regel auf einer begrenzten Anzahl von Daten durchgeführt, die auf einen zentralen Speicherplatz geladen werden. In Big Data-Umgebungen hingegen, wo die Datenmengen sehr groß sind und die Verarbeitungsgeschwindigkeit eine entscheidende Rolle spielt, wird ELT bevorzugt. Hier werden die Daten zunächst in den Speicher geladen und anschließend in Echtzeit oder nahezu Echtzeit transformiert, um die Verarbeitungsgeschwindigkeit zu erhöhen.

Wie werden Fehler in ETL- und ELT-Prozessen behandelt?

Fehlerbehandlung ist ein wichtiger Bestandteil von ETL- und ELT-Prozessen. In ETL-Prozessen werden Fehler in der Regel während der Extraktion, Transformation und Ladephase behandelt.

  • Fehler bei der Extraktion können durch Probleme mit der Verbindung zu den Datenquellen oder durch ungültige Abfrageparameter verursacht werden. Sie können durch Überprüfungen der Verbindungen und der Abfrageparameter sowie durch die Verwendung von Fehlerprotokollen behoben werden.
  • Fehler bei der Transformation können durch ungültige Daten, fehlende Felder oder inkonsistente Datenstrukturen verursacht werden. Sie können durch die Verwendung von Fehlerprotokollen, die Überprüfung von Daten vor der Transformation und die Verwendung von Regeln und Constraints behoben werden.
  • Fehler beim Laden können durch Probleme mit der Datenbankstruktur, dem Zielverzeichnis oder dem Datenformat verursacht werden. Sie können durch die Verwendung von Fehlerprotokollen, die Überprüfung des Zielverzeichnisses und die Verwendung von Regeln und Constraints behoben werden.

In ELT-Prozessen werden Fehler in der Regel während der Ladephase und der Transformation behandelt.

  • Fehler beim Laden können durch Probleme mit der Datenbankstruktur, dem Zielverzeichnis oder dem Datenformat verursacht werden. Sie können durch die Verwendung von Fehlerprotokollen, die Überprüfung des Zielverzeichnisses und die Verwendung von Regeln und Constraints behoben werden.
  • Fehler bei der Transformation können durch ungültige Daten, fehlende Felder oder inkonsistente Datenstrukturen verursacht werden. Sie können durch die Verwendung von Fehlerprotokollen, die Überprüfung von Daten nach dem Laden und die Verwendung von Regeln und Constraints behoben werden.

In beiden Prozessen, ETL und ELT, ist es wichtig, Regeln und Constraints zu definieren, um Fehler frühzeitig zu erkennen und zu beheben, sowie Fehlerprotokolle zu erstellen, um Fehler nachverfolgen und beheben zu können.

Wie wird die Leistung von ETL- und ELT-Prozessen gemessen?

Die Leistung von ETL- und ELT-Prozessen kann anhand verschiedener Metriken gemessen werden. Einige häufig verwendete Metriken sind:

  • Durchlaufzeit: Die Zeit, die von der Extraktion bis zur Ladeoperation benötigt wird, wird als Durchlaufzeit bezeichnet. Sie gibt Auskunft darüber, wie lange der Prozess insgesamt dauert und kann verwendet werden, um die Geschwindigkeit des Prozesses zu messen.
  • Datenmenge: Die Menge an Daten, die in einem bestimmten Zeitraum extrahiert, transformiert und geladen werden, kann verwendet werden, um die Kapazität des Prozesses zu messen.
  • Fehlerrate: Die Anzahl der Fehler im Verhältnis zur Gesamtzahl der Daten, die verarbeitet werden, kann verwendet werden, um die Zuverlässigkeit des Prozesses zu messen.
  • Verfügbarkeit: Die Zeit, die der Prozess in Betrieb ist und verfügbar ist, kann verwendet werden, um die Verfügbarkeit des Prozesses zu messen.
  • Latenz: Die Zeit, die benötigt wird, um eine Anfrage zu bearbeiten und eine Antwort zurückzugeben, kann verwendet werden, um die Reaktionszeit des Prozesses zu messen.

Die Wahl der richtigen Metrik hängt von den Anforderungen und Zielen des Projekts ab. Es ist wichtig, sowohl quantitative als auch qualitative Metriken zu verwenden, um ein umfassenderes Verständnis der Leistung des Prozesses zu erhalten.

Welche Tools und Technologien werden häufig in ETL- und ELT-Prozessen verwendet?

Es gibt eine Vielzahl von Tools und Technologien, die in ETL- und ELT-Prozessen verwendet werden können. Einige häufig verwendete Tools und Technologien sind:

  • ETL-Tools: Tools wie Informatica PowerCenter, Talend, IBM DataStage und SAP Data Services werden häufig in traditionellen ETL-Prozessen verwendet, um die Extraktion, Transformation und Ladung von Daten zu automatisieren.
  • ELT-Tools: Tools wie Apache Nifi, Apache Kafka und Apache Storm werden häufig in Big Data-Umgebungen verwendet, um die Extraktion, Ladung und Transformation von Daten in Echtzeit oder nahezu Echtzeit zu ermöglichen.
  • Datenbank-Management-Systeme: Data Warehouses wie Oracle, Teradata und Amazon Redshift werden häufig als Ziel für geladene Daten verwendet.
  • Cloud-basierte Tools: Cloud-basierte Tools wie Amazon Glue, Google Cloud Dataflow und Microsoft Azure Data Factory werden häufig in Cloud-Umgebungen verwendet, um die Extraktion, Transformation und Ladung von Daten zu automatisieren.
  • Programmiersprachen: Programmiersprachen wie Python, Java, und SQL werden oft verwendet, um komplexe Transformationen, Validierungen und Logik in ETL/ELT Prozessen zu implementieren.

Es ist wichtig zu beachten, dass es keine “eine Größe passt für alle” Lösungen gibt und die Wahl des Tools oder Technologie von den Anforderungen und Zielen des Projekts abhängig sind.

Welche Best Practices sollten bei der Implementierung von ETL- und ELT-Prozessen beachtet werden?

Bei der Implementierung von ETL- und ELT-Prozessen sollten folgende Best Practices beachtet werden:

  1. Verwenden Sie eine modulare Architektur, um Wartbarkeit und Skalierbarkeit zu erleichtern.
  2. Verwenden Sie eine automatisierte Teststrategie, um die Integrität der Daten zu gewährleisten.
  3. Verwenden Sie eine Versionierung für Ihre ETL-Prozesse, um Änderungen nachverfolgen zu können.
  4. Verwenden Sie eine robuste Fehlerbehandlung, um Prozessfehler schnell identifizieren und beheben zu können.
  5. Verwenden Sie eine Überwachungslösung, um die Leistung und die Ausführung Ihrer Prozesse zu überwachen.
  6. Verwenden Sie standardisierte Metadaten, um die Datenqualität und die Verwaltbarkeit zu verbessern.
  7. Verwenden Sie ELT anstelle von ETL, wenn es die Anforderungen erfüllt, um die Leistung zu verbessern und die Kosten zu reduzieren.
  8. Verwenden Sie DWH und BI-Tools, um die Datenanalyse zu vereinfachen und die Business Intelligence zu verbessern.

Fazit

Cloud Data Warehouses haben eine neue Dimension der Datenintegration eröffnet, aber die Entscheidung zwischen ETL und ELT hängt von den Bedürfnissen eines Teams ab.

Obwohl ELT Vorteile bietet, werden einige Teams bei ETL bleiben, weil die Methode für ihre spezielle Bereitstellung sinnvoll ist, ob mit oder ohne Legacy-Infrastruktur.

Die SQL-Anweisung CASE

Die CASE-Anweisung durchläuft die Bedingungen und gibt einen Wert zurück, wenn die erste Bedingung erfüllt ist (wie eine if-then-else-Anweisung). Sobald also eine Bedingung erfüllt ist, wird das Lesen beendet und das Ergebnis zurückgegeben. Wenn keine Bedingung erfüllt ist, wird der Wert aus der ELSE-Klausel zurückgegeben.

Wenn es keinen ELSE-Teil gibt und keine Bedingung erfüllt ist, wird NULL zurückgegeben.

Ausgangstabelle:

Abfrage

Inhalt der Abfrage: Wir wollen eine weitere Spalte „Großstadt“ hinzufügen in der bei Städten, wie München oder Berlin, der Wert „Großstadt“ in die selbe Zeile kommt.

SELECT 
    event_date_user,
    user_city,
        CASE user_city 
            WHEN 'Munich' THEN 'big city'
            WHEN 'Berlin' THEN 'big city'
            ELSE 'Others'
        END
        AS big_city,

FROM `privat-327611.analytics_266663932.user_city`

Der SQL EXISTS-Operator

Der EXISTS-Operator wird verwendet, um zu prüfen, ob ein Datensatz in einer Unterabfrage vorhanden ist.

Der EXISTS-Operator gibt TRUE zurück, wenn die Unterabfrage einen oder mehrere Datensätze zurückgibt.

Beispiel-Abfrage

Ausgangstabellen:

Wir haben eine Tabelle mit den Pageviews und eine mit den Anzahl pro Nutzer pro Tag:

Inhalt der Abfrage: Wir wolllen jetzt nur die Tage Anzeigen lassen bei denen auch mindestens 60 Pageviews erzielt wurden:
SELECT 
    event_date_user,
    user,
FROM `privat-327611.analytics_266663932.user_basic`
WHERE EXISTS (SELECT event_date FROM `privat-327611.analytics_266663932.pageviews_basic` WHERE event_date = event_date_user AND page_views_pageview > 60)

Die SQL HAVING-Klausel

Die HAVING-Klausel wurde zu SQL hinzugefügt, weil das Schlüsselwort WHERE nicht mit Aggregatfunktionen verwendet werden kann.

Beispiel-Abfrage

Ausgangstabelle:

Inhalt der Beispielabfrage: Wir haben untereinander mehrere User-IDs, zu denen jeweils ein Datum zugeordnet ist. Wir wollen mit der Abfrage herausfinden, wie viele Nutzer wir pro Tag hatten. Wir gruppieren, deshalb anhand des Datums und zählen die Anzahl der Nutzer. ZUSÄTZLICH wollen wir aber ausschließlich die Tage angezeigt bekommen, die mindestens 8 Nutzer hatten:

SELECT 
    event_date_user,
    COUNT(user_pseudo_id) AS count_user,
FROM `privat-327611.analytics_266663932.base`
GROUP BY event_date_user
HAVING count_user >= 8