PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Menggabungkan rekor bergabung terbaru per minggu

Anda memerlukan satu item data per minggu dan sasaran (sebelum menggabungkan jumlah per perusahaan). Itu hanya CROSS JOIN antara generate_series() dan goals . Bagian yang (mungkin) mahal adalah untuk mendapatkan state saat ini dari updates untuk setiap. Suka @Paul sudah disarankan , sebuah LATERAL bergabung sepertinya alat terbaik. Lakukan hanya untuk updates , dan gunakan teknik yang lebih cepat dengan LIMIT 1 .

Dan sederhanakan penanganan tanggal dengan date_trunc() .

SELECT w_start
     , g.company_id
     , count(*) FILTER (WHERE u.status = 'green') AS green_count
     , count(*) FILTER (WHERE u.status = 'amber') AS amber_count
     , count(*) FILTER (WHERE u.status = 'red')   AS red_count
FROM   generate_series(date_trunc('week', NOW() - interval '2 months')
                     , date_trunc('week', NOW())
                     , interval '1 week') w_start
CROSS  JOIN goals g
LEFT   JOIN LATERAL (
   SELECT status
   FROM   updates
   WHERE  goal_id = g.id
   AND    created_at < w_start
   ORDER  BY created_at DESC
   LIMIT  1
   ) u ON true
GROUP  BY w_start, g.company_id
ORDER  BY w_start, g.company_id;

Untuk membuat ini cepat anda memerlukan indeks multikolom :

CREATE INDEX updates_special_idx ON updates (goal_id, created_at DESC, status);

Urutan menurun untuk created_at adalah yang terbaik, tetapi tidak sepenuhnya diperlukan. Postgres dapat memindai indeks mundur hampir sama cepatnya. ( Namun, tidak berlaku untuk urutan terbalik dari beberapa kolom. )

Indeks kolom di itu memesan. Mengapa?

Dan kolom ketiga status hanya ditambahkan untuk memungkinkan pemindaian hanya indeks yang cepat di updates . Kasus terkait:

1.000 sasaran selama 9 minggu (interval 2 bulan Anda tumpang tindih dengan setidaknya 9 minggu) hanya memerlukan 9k indeks pencarian untuk tabel ke-2 yang hanya terdiri dari 1.000 baris. Untuk tabel kecil seperti ini, kinerja seharusnya tidak menjadi masalah. Namun begitu Anda memiliki beberapa ribu lebih di setiap tabel, kinerja akan menurun dengan pemindaian berurutan.

w_start mewakili awal setiap minggu. Akibatnya, penghitungan adalah untuk awal minggu. Anda bisa masih mengekstrak tahun dan minggu (atau detail lainnya mewakili minggu Anda), jika Anda bersikeras:

   EXTRACT(isoyear from w_start) AS year
 , EXTRACT(week    from w_start) AS week

Terbaik dengan ISOYEAR , seperti yang dijelaskan @Paul.

SQL Fiddle.

Terkait:



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara membuat indeks pada bidang JSON di Postgres?

  2. Baca jumlah pada tabel postgres

  3. Mengalihkan proyek Django dari backend sqlite3 ke postgresql gagal saat memuat datadump

  4. Menyimpan ARRAY PostgreSQL dari nilai ENUM

  5. Berikan hak istimewa pada tabel mendatang di PostgreSQL?