W tym pytaniu jest więcej, niż mogłoby się wydawać.
Prosta wersja
To dużo szybciej i prościej:
SELECT property_name
,(count(value_a = value_b OR NULL) * 100) / count(*) AS pct
FROM my_obj
GROUP BY 1;
Wynik:
property_name | pct
--------------+----
prop_1 | 17
prop_2 | 43
Jak?
-
W ogóle nie potrzebujesz do tego funkcji.
-
Zamiast liczyć
value_b
(od czego nie musisz zaczynać) i obliczając sumę, użyjcount(*)
za całość. Szybciej, prościej. -
Zakłada się, że nie masz
NULL
wartości. Tj. obie kolumny są zdefiniowaneNOT NULL
. Brakuje informacji w Twoim pytaniu.
Jeśli nie, pierwotne zapytanie prawdopodobnie nie robi tego, co Twoim zdaniem robi . Jeśli którakolwiek z wartości ma wartość NULL, Twoja wersja w ogóle nie liczy tego wiersza. Możesz nawet sprowokować dzielenie przez zero wyjątek w ten sposób.
Ta wersja działa również z NULL.count(*)
generuje liczbę wszystkich wierszy, niezależnie od wartości. -
Oto jak działa licznik:
TRUE OR NULL = TRUE FALSE OR NULL = NULL
count()
ignoruje wartości NULL. Voila. -
Pierwszeństwo operatora określa, że
=
wiąże przedOR
. Możesz dodać nawiasy, aby było jaśniej:count ((value_a = value_b) OR FALSE)
-
Możesz zrobić to samo z
count NULLIF(<expression>, FALSE)
-
Typ wyniku
count()
jestbigint
domyślnie.
Działbigint / bigint
, obcina cyfry ułamkowe .
Uwzględnij cyfry ułamkowe
Użyj 100.0
(z cyfrą ułamkową), aby wymusić obliczenie jako numeric
i tym samym zachować cyfry ułamkowe.
Możesz użyć round()
z tym:
SELECT property_name
,round((count(value_a = value_b OR NULL) * 100.0) / count(*), 2) AS pct
FROM my_obj
GROUP BY 1;
Wynik:
property_name | pct
--------------+-------
prop_1 | 17.23
prop_2 | 43.09
Na marginesie:
Używam value_a
zamiast valueA
. Nie używaj niecytowanych identyfikatorów z mieszanymi literami w PostgreSQL. Widziałem zbyt wiele rozpaczliwych pytań wynikających z tego szaleństwa. Jeśli zastanawiasz się, o czym mówię, przeczytaj rozdział „Identyfikatory i słowa kluczowe” w podręczniku.