PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Lewe sprzężenie zewnętrzne działające jak sprzężenie wewnętrzne

Zapytanie można prawdopodobnie uprościć do:

SELECT u.name AS user_name
     , p.name AS project_name
     , tl.created_on::date AS changeday
     , coalesce(sum(nullif(new_value, '')::numeric), 0)
     - coalesce(sum(nullif(old_value, '')::numeric), 0) AS hours
FROM   users             u
LEFT   JOIN (
        tasks            t 
   JOIN fixins           f  ON  f.id = t.fixin_id
   JOIN projects         p  ON  p.id = f.project_id
   JOIN task_log_entries tl ON  tl.task_id = t.id
                           AND  tl.field_id = 18
                           AND (tl.created_on IS NULL OR
                                tl.created_on >= '2013-09-08' AND
                                tl.created_on <  '2013-09-09') -- upper border!
       ) ON t.assignee_id = u.id
WHERE  EXISTS (SELECT 1 FROM tasks t1 WHERE t1.assignee_id = u.id)
GROUP  BY 1, 2, 3
ORDER  BY 1, 2, 3;

Spowoduje to zwrócenie wszystkich użytkowników, którzy kiedykolwiek mieli jakiekolwiek zadanie.
Plus dane na projekty i dzień gdzie dane istnieją w określonym zakresie dat w task_log_entries .

Główne punkty

  • funkcja agregująca sum() ignoruje NULL wartości. COALESCE() za wiersz nie jest już wymagane, gdy tylko przekształcisz obliczenia jako różnicę dwóch sum:

     ,coalesce(sum(nullif(new_value, '')::numeric), 0) -
      coalesce(sum(nullif(old_value, '')::numeric), 0) AS hours
    

    Jednak jeśli możliwe, że wszystkie kolumny zaznaczenia mają NULL lub puste ciągi, zawiń sumy w COALESCE raz.
    Używam numeric zamiast float , bezpieczniejsza alternatywa, aby zminimalizować błędy zaokrąglania.

  • Twoja próba uzyskania różnych wartości z połączenia users i tasks jest daremne, ponieważ dołączasz do tasks jeszcze raz niżej. Spłaszcz całe zapytanie, aby było prostsze i szybsze.

  • Te odniesienia pozycyjne to tylko notacyjna wygoda:

    GROUP BY 1, 2, 3
    ORDER BY 1, 2, 3
    

    ... robiąc to samo, co w pierwotnym zapytaniu.

  • Aby uzyskać date z timestamp możesz po prostu przesłać na date :

    tl.created_on::date AS changeday
    

    Ale znacznie lepiej jest testować z oryginalnymi wartościami w WHERE klauzula lub JOIN warunek (jeśli to możliwe i jest to możliwe tutaj), aby Postgres mógł używać zwykłych indeksów w kolumnie (jeśli są dostępne):

     AND (tl.created_on IS NULL OR
          tl.created_on >= '2013-09-08' AND
          tl.created_on <  '2013-09-09')  -- next day as excluded upper border
    

    Pamiętaj, że literał daty jest konwertowany na timestamp o 00:00 dnia w aktualnym czasie strefa . Musisz wybrać następny dzień i wyklucz to jako górna granica. Lub podaj bardziej wyraźny literał znacznika czasu, taki jak '2013-09-22 0:0 +2':: timestamptz . Więcej o wykluczeniu górnej granicy:

  • Dla wymagania every user who has ever been assigned to a task dodaj WHERE klauzula:

    WHERE EXISTS (SELECT 1 FROM tasks t1 WHERE t1.assignee_id = u.id)
    
  • Co najważniejsze :LEFT [OUTER] JOIN zachowuje wszystkie wiersze na lewo od połączenia. Dodawanie WHERE klauzula po prawej tabela może unieważnić ten efekt. Zamiast tego przenieś wyrażenie filtra do JOIN klauzula. Więcej wyjaśnień tutaj:

  • Nawiasy może służyć do wymuszenia kolejności łączenia tabel. Rzadko potrzebne do prostych zapytań, ale bardzo przydatne w tym przypadku. Korzystam z tej funkcji, aby dołączyć do tasks , fixins , projects i task_log_entries przed połączeniem z lewej strony do users - bez podzapytania.

  • aliasy tabel ułatwiają pisanie złożonych zapytań.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Postgre SQL ignoruje warunek filtrowania, jeśli wartość ma wartość null

  2. Postgresql - czy istnieje sposób na wyłączenie wyświetlania instrukcji INSERT podczas wczytywania z pliku?

  3. Problem z accepts_nested_attributes_for w Railsach 5.0.0.beta3, opcja -api

  4. Django, mod_wsgi, psycopg2 Nieprawidłowo skonfigurowane:Błąd podczas ładowania modułu psycopg2:Brak modułu o nazwie _psycopg

  5. Jak skonfigurować PostgreSQL do korzystania z uwierzytelniania Windows?