PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Заявка с LEFT JOIN не връща редове за брой 0

Поправете LEFT JOIN

Това трябва да работи:

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;

Имахте LEFT [OUTER] JOIN но по-късният WHERE условията го накараха да действа като обикновено [INNER] JOIN .
Преместете условието(ата) в JOIN клауза, за да работи по предназначение. По този начин само редове, които отговарят на всички тези условия, се съединяват на първо място (или колони от дясно таблицата се попълва с NULL). Както сте го имали, съединените редове се тестват за допълнителни условия практически след LEFT JOIN и се премахват, ако не преминат, точно както при обикновен JOIN .

count() никога не връща NULL като начало. Това е изключение сред агрегатните функции в това отношение. Следователно, COALESCE(COUNT(col)) никога има смисъл, дори и с допълнителни параметри. Ръководството:

Трябва да се отбележи, че с изключение на count , тези функции връщат нулева стойност, когато не са избрани редове.

Удебелен акцент мой. Вижте:

  • Пребройте броя на атрибутите, които са NULL за ред

count() трябва да е в колона, дефинирана NOT NULL (като e.id ), или където условието за присъединяване гарантира NOT NULL (e.organisation_id , e.item_template_id , или e.used ) в примера.

Тъй като used е тип boolean , изразът e.used = true е шум, който изгаря само до e.used .

Тъй като o.name не е дефиниран UNIQUE NOT NULL , може да искате да GROUP BY o.id вместо това (id като ПК) - освен ако не възнамерявате за сгъване на редове със същото име (включително NULL).

Първо обобщете, присъединете се по-късно

Ако повечето или всички редове от exam_items се отчитат в процеса, тази еквивалентна заявка обикновено е значително по-бърза / по-евтина:

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;

(Това се предполага, че не искате да сгъвате редове със същото име, както е споменато по-горе – типичният случай.)

Сега можем да използваме по-бързия / по-прост count(*) в подзаявката и не се нуждаем от GROUP BY във външния SELECT .

Вижте:

  • Множество извиквания на array_agg() в една заявка


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Грешка в PostgreSQL:Фатално:потребителското име на ролята не съществува

  2. Как да извършвате операции за актуализиране на колони от тип JSONB в Postgres 9.4

  3. Цената на безплатната реклама на PostgreSQL

  4. Време за изчакване на заявка в pg-promise

  5. Вмъкване на няколко реда в една таблица въз основа на число в друга таблица