Wyjaśnienie błędu
Bezpośrednią przyczyną komunikatu o błędzie jest to, że każde jawne JOIN
wiąże mocniej niż przecinek (,
), co w przeciwnym razie jest równoważne z CROSS JOIN
, ale (zgodnie z dokumentacją
):
Pogrubienie focus mine.
To jest przyczyna twojego błędu. możesz napraw to:
FROM appointment_intakes
CROSS JOIN LATERAL jsonb_object_keys(data #> '{products}') keys
INNER JOIN appointment_intake_users ON ...
Ale to nie był jedyny problem. Czytaj dalej.
Można by argumentować, że Postgres powinien widzieć, że LATERAL
ma sens tylko w połączeniu ze stołem po lewej stronie. Ale tak nie jest.
Założenie
Dodałem aliasy tabel i zakwalifikowałem wszystkie nazwy kolumn jako podejrzane. Będąc przy tym, uprościłem odwołania JSON i przyciąłem trochę szumu.To zapytanie jest nadal niepoprawne :
SELECT i.data ->> 'id' AS id,
i.data ->> 'name' AS name,
i.data ->> 'curator' AS curator,
i.data -> '$isValid' AS "$isValid",
i.data -> 'customer' AS customer,
i.data -> '$createdTS' AS "$createdTS",
i.data -> '$updatedTS' AS "$updatedTS",
i.data -> '$isComplete' AS "$isComplete",
count(k.keys)::numeric AS "numProducts",
u.created_at
FROM appointment_intakes i
, jsonb_object_keys(i.data -> 'products') AS k(keys)
JOIN appointment_intake_users u ON u.appointment_intake_id = i.id
#{where_clause}
GROUP BY i.id
Nieprzetworzone zapytanie
W oparciu o powyższe i kilka innych założeń rozwiązaniem może być wykonanie liczenia w podzapytaniu:
SELECT i.data ->> 'id' AS id,
i.data ->> 'name' AS name,
i.data ->> 'curator' AS curator,
i.data -> '$isValid' AS "$isValid",
i.data -> 'customer' AS customer,
i.data -> '$createdTS' AS "$createdTS",
i.data -> '$updatedTS' AS "$updatedTS",
i.data -> '$isComplete' AS "$isComplete",
(SELECT count(*)::numeric
FROM jsonb_object_keys(i.data -> 'products')) AS "numProducts",
min(u.created_at) AS created_at
FROM appointment_intakes i
JOIN appointment_intake_users u ON u.appointment_intake_id = i.id
-- #{where_clause}
GROUP BY i.id;
Ponieważ potrzebujesz tylko licznika, przekonwertowałem Twój LATERAL
połączyć w skorelowane podzapytanie, unikając w ten sposób różnych problemów wynikających z wielu połączonych łączeń 1:n. Więcej:
- Jaka jest różnica między LATERAL JOIN a podzapytanie w PostgreSQL?
- Dwa lewe sprzężenia SQL generować błędny wynik
potrzebujesz aby poprawnie uciec przed identyfikatorami, użyj przygotowanej instrukcji i przekaż wartości jako wartości. Nie łącz wartości w ciągu zapytania. To zaproszenie do losowych błędów lub wstrzyknięcia SQL ataki. Ostatni przykład dla PHP: