Aby pominąć wiersz w wyniku jeśli którykolwiek z źródła wiersze dla tego samego id
ma value IS NULL
, rozwiązanie w Postgresie byłoby użycie funkcji agregującej every()
lub (synonim ze względów historycznych) bool_and()
w HAVING
klauzula:
SELECT id
, max(case when colID = 1 then value else '' end) AS fn
, max(case when colID = 2 then value else '' end) AS ln
, max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
HAVING every(value IS NOT NULL);
Wyjaśnij
Twoja próba z WHERE
klauzula po prostu wyeliminuje jeden wiersz źródłowy dla id = 3
w twoim przykładzie (ten z colID = 1
), pozostawiając jeszcze dwa dla tego samego id
. Więc nadal otrzymujemy wiersz dla id = 3
w wyniku po agregacji.
Ale ponieważ nie mamy wiersza z colID = 1
, otrzymujemy pusty ciąg (uwaga:nie NULL
wartość!) dla fn
w wyniku dla id = 3
.
Szybszym rozwiązaniem w Postgresie byłoby użycie crosstab()
. Szczegóły:
Inne RDBMS
Podczas gdy EVERY
jest zdefiniowany w standardzie SQL:2008, wiele RDBMS go nie obsługuje, prawdopodobnie dlatego, że niektóre z nich mają podejrzane implementacje typu logicznego. (Nie upuszczaj żadnych nazw, takich jak "MySQL" lub "Oracle" ...). Prawdopodobnie możesz zastąpić wszędzie (w tym Postgres) za pomocą:
SELECT id
, max(case when colID = 1 then value else '' end) AS fn
, max(case when colID = 2 then value else '' end) AS ln
, max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
HAVING count(*) = count(value);
Ponieważ count()
nie liczy wartości NULL. W MySQL istnieje również bit_and()
.Więcej pod tym pytaniem: