Sửa lỗi LEFT JOIN
Điều này sẽ hoạt động:
SELECT o.name AS organisation_name, count(e.id) AS total_used
FROM organisations o
LEFT JOIN exam_items e ON e.organisation_id = o.id
AND e.item_template_id = #{sanitize(item_template_id)}
AND e.used
GROUP BY o.name
ORDER BY o.name;
Bạn đã có LEFT [OUTER] JOIN
nhưng WHERE
muộn hơn các điều kiện khiến nó hoạt động giống như một [INNER] JOIN
đơn giản .
Di chuyển (các) điều kiện đến JOIN
để làm cho nó hoạt động như dự định. Bằng cách này, chỉ các hàng đáp ứng tất cả các điều kiện này mới được nối ở vị trí đầu tiên (hoặc các cột từ bên phải bảng được điền bằng NULL). Giống như bạn đã có, các hàng đã nối sẽ được kiểm tra các điều kiện bổ sung hầu như sau LEFT JOIN
và bị xóa nếu chúng không đạt, giống như với JOIN
đơn giản .
count()
không bao giờ trả về NULL để bắt đầu với. Đó là một ngoại lệ trong số các hàm tổng hợp về mặt này. Do đó, không bao giờ có ý nghĩa, ngay cả với các tham số bổ sung. Hướng dẫn sử dụng:COALESCE(COUNT(col))
Cần lưu ý rằng ngoại trừ
count
, các hàm này trả về giá trị null khi không có hàng nào được chọn.
Tôi nhấn mạnh đậm. Xem:
- Đếm số thuộc tính là NULL cho một hàng
count()
phải nằm trên một cột được xác định NOT NULL
(như e.id
), hoặc nơi điều kiện tham gia đảm bảo NOT NULL
(e.organisation_id
, e.item_template_id
hoặc e.used
) trong ví dụ.
Kể từ khi used
là loại boolean
, biểu thức e.used = true
là tiếng ồn chỉ còn e.used
.
Kể từ khi o.name
không được xác định UNIQUE NOT NULL
, bạn có thể muốn GROUP BY o.id
thay vào đó (id
là PK) - trừ khi bạn có ý định để gấp các hàng có cùng tên (bao gồm cả NULL).
Tổng hợp trước, tham gia sau
Nếu hầu hết hoặc tất cả các hàng của exam_items
được tính trong quá trình này, truy vấn tương đương này thường nhanh hơn / rẻ hơn đáng kể:
SELECT o.id, o.name AS organisation_name, e.total_used
FROM organisations o
LEFT JOIN (
SELECT organisation_id AS id -- alias to simplify join syntax
, count(*) AS total_used -- count(*) = fastest to count all
FROM exam_items
WHERE item_template_id = #{sanitize(item_template_id)}
AND used
GROUP BY 1
) e USING (id)
ORDER BY o.name, o.id;
(Điều này giả sử rằng bạn không muốn gấp các hàng có cùng tên như đã đề cập ở trên - trường hợp điển hình.)
Giờ đây, chúng ta có thể sử dụng count(*)
nhanh hơn / đơn giản hơn trong truy vấn con và chúng ta không cần GROUP BY
trong SELECT
bên ngoài .
Xem:
- Nhiều lệnh gọi array_agg () trong một truy vấn duy nhất