programowanieBI/analityk, Data Engineer

Jak poprawnie zrealizować zliczanie unikalnych użytkowników według złożonego zestawu kryteriów, z uwzględnieniem NULL i duplikatów, używając konstrukcji DISTINCT, COUNT, GROUP BY w SQL?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Historia pytania

Raporty dotyczące unikalnych użytkowników są niezbędne do analizy i statystyki. Jednak w danych rzeczywistych często występują duplikaty kont, wartości NULL (na przykład brakujący email) i należy uwzględniać różne kryteria (na przykład unikalność według imienia, maila, ip, a czasami ich kombinacje).

Problem

Typowy błąd — liczenie COUNT(DISTINCT user_id), nie uwzględniając, że w odpowiednich kolumnach są NULL lub nieoczywiste duplikaty (na przykład jedna osoba z różnymi emailami, lub kilka wierszy z jednym user_id i różnym statusem). Złożone zapytania z GROUP BY mogą dawać nieprawidłowe wyniki, jeśli logika unikalności nie jest przemyślana.

Rozwiązanie

Ważne jest łączenie konstrukcji DISTINCT, GROUP BY i filtrowania NULL. Czasami konieczne jest wcześniejsze przetworzenie danych w CTE lub zagnieżdżonym podzapytaniu, grupując według potrzebnego zestawu cech.

Przykład kodu:

-- Zliczanie unikalnych użytkowników według emaila i ip, ignorując NULL SELECT COUNT(*) AS unique_users FROM ( SELECT DISTINCT email, ip_address FROM users WHERE email IS NOT NULL AND ip_address IS NOT NULL ) u;

Kluczowe cechy:

  • DISTINCT nie uwzględnia wierszy z NULL w jakiejkolwiek z wymienionych kolumn
  • Do cross-grupowania lepiej używać GROUP BY według kombinacji pól
  • Przy pracy z duplikatami dane często trzeba "oczyścić" wcześniej

Pytania z podstępem.

Czy COUNT(DISTINCT ...) uwzględnia wiersze z NULL?

Nie: jeśli przynajmniej jedna z kolumn na liście DISTINCT ma wartość NULL, taka kombinacja jest uznawana za osobną unikalną (NULL nie jest równy NULL według standardu SQL). Zwykle wygodniej jest najpierw usunąć NULL poprzez filtrację.


Czy można porównywać NULL z NULL przez DISTINCT?

W SQL każda para wartości NULL jest uznawana za różną, dlatego każdy wiersz z NULL w jakiejkolwiek kolumnie będzie uznawany za osobny. Należy stosować filtrację przez IS NOT NULL.


Czy GROUP BY zawsze daje taki sam wynik jak DISTINCT?

Nie: GROUP BY tworzy po jednym wierszu dla każdej unikalnej kombinacji wartości, a DISTINCT po prostu usuwa duplikaty. W wielu przypadkach wyniki są różne, szczególnie gdy stosuje się agregację.

Typowe błędy i antywzorce

  • Nieoczywiste filtrowanie wartości NULL
  • Niejawne duplikowanie danych przed agregacją
  • Nieprawidłowe łączenie DISTINCT z agregacją na różnych poziomach hierarchii

Przykład z życia

Negatywny przypadek

Analityk biznesowy przygotowuje raport dotyczący unikalnych klientów przez COUNT(DISTINCT user_id), podczas gdy user_id w rzeczywistości może być NULL lub się duplikować (na przykład konta tymczasowe). Rzeczywista liczba użytkowników okazuje się być większa niż w rzeczywistości — zniekształcone wskaźniki w raporcie.

Plusy:

  • Szybka realizacja raportu

Minusy:

  • Nieprawidłowe decyzje biznesowe z powodu błędnej metryki

Pozytywny przypadek

Analityk najpierw oczyszcza dane, filtruje NULL oraz oczywiste duplikaty w podzapytaniach, a także wykorzystuje operacje SET do złożonych kryteriów unikalności.

Plusy:

  • Prawidłowe i przejrzyste metryki
  • Ważne decyzje biznesowe i KPI

Minusy:

  • Bardziej złożone zapytanie, wymaga jakości testów na danych testowych