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

Temukan dan jumlahkan rentang tanggal dengan catatan yang tumpang tindih di postgresql

demo:db<>biola (menggunakan kumpulan data lama dengan bagian A-B yang tumpang tindih)

Penafian: Ini berfungsi untuk interval hari bukan untuk cap waktu. Persyaratan untuk ts datang kemudian.

SELECT
    s.acts,
    s.sum,
    MIN(a.start) as start,
    MAX(a.end) as end
FROM (
    SELECT DISTINCT ON (acts)
        array_agg(name) as acts,
        SUM(count)
    FROM
        activities, generate_series(start, "end", interval '1 day') gs
    GROUP BY gs
    HAVING cardinality(array_agg(name)) > 1
) s
JOIN activities a
ON a.name = ANY(s.acts)
GROUP BY s.acts, s.sum
  1. generate_series menghasilkan semua tanggal antara awal dan akhir. Jadi setiap tanggal ada aktivitas mendapat satu baris dengan count tertentu
  2. Mengelompokkan semua tanggal, menggabungkan semua aktivitas yang ada dan jumlah penghitungannya
  3. HAVING menyaring tanggal di mana hanya ada satu aktivitas
  4. Karena ada hari yang berbeda dengan aktivitas yang sama, kami hanya membutuhkan satu perwakilan:Filter semua duplikat dengan DISTINCT ON
  5. Gabungkan hasil ini dengan tabel asli untuk memulai dan mengakhiri. (perhatikan bahwa "akhir" adalah kata yang dicadangkan di Postgres, Anda sebaiknya mencari nama kolom lain!). Lebih nyaman untuk kehilangan mereka sebelumnya, tetapi mungkin untuk mendapatkan data ini di dalam subkueri.
  6. Kelompokkan ini bergabung untuk mendapatkan tanggal paling awal dan terbaru dari setiap interval.

Berikut adalah versi untuk stempel waktu:

demo:db<>biola

WITH timeslots AS (
    SELECT * FROM (
        SELECT
            tsrange(timepoint, lead(timepoint) OVER (ORDER BY timepoint)),
            lead(timepoint) OVER (ORDER BY timepoint)     -- 2
        FROM (
            SELECT 
                unnest(ARRAY[start, "end"]) as timepoint  -- 1 
            FROM
                activities
            ORDER BY timepoint
        ) s
    )s  WHERE lead IS NOT NULL                            -- 3
)
SELECT 
    GREATEST(MAX(start), lower(tsrange)),                 -- 6
    LEAST(MIN("end"), upper(tsrange)),
    array_agg(name),                                      -- 5
    sum(count)
FROM 
    timeslots t
JOIN activities a
ON t.tsrange && tsrange(a.start, a.end)                   -- 4
GROUP BY tsrange
HAVING cardinality(array_agg(name)) > 1

Ide utamanya adalah untuk mengidentifikasi kemungkinan slot waktu. Jadi saya mengambil setiap waktu yang diketahui (baik awal dan akhir) dan memasukkannya ke dalam daftar yang diurutkan. Jadi saya dapat mengambil waktu derek pertama yang diketahui (17:00 dari start A dan 18:00 dari start B) dan memeriksa interval mana yang ada di dalamnya. Kemudian saya memeriksanya untuk tanggal 2 dan 3, lalu untuk tanggal 3 dan 4 dan seterusnya.

Di slot waktu pertama hanya A yang cocok. Di detik 18-19 juga B pas. Di slot berikutnya 19-20 juga C, dari 20 ke 20:30 A tidak pas lagi, hanya B dan C. Berikutnya 20:30-22 di mana hanya B yang cocok, akhirnya 22-23 D ditambahkan ke B dan yang terakhir hanya D yang cocok dengan 23-23:30.

Jadi saya mengambil daftar waktu ini dan menggabungkannya dengan tabel aktivitas di mana intervalnya berpotongan. Setelah itu hanya pengelompokan berdasarkan slot waktu dan jumlahkan hitungan Anda.

  1. ini menempatkan kedua t baris ke dalam satu larik yang elemennya diperluas menjadi satu baris per elemen dengan unnest . Jadi saya mendapatkan semua waktu menjadi satu kolom yang bisa dipesan dengan mudah
  2. menggunakan lead fungsi jendela memungkinkan untuk mengambil nilai dari baris berikutnya ke yang sekarang. Jadi saya bisa membuat rentang waktu dari kedua nilai ini dengan tsrange
  3. Filter ini diperlukan karena baris terakhir tidak memiliki "nilai berikutnya". Ini membuat NULL nilai yang ditafsirkan oleh tsrange sebagai tak terhingga. Jadi ini akan membuat slot waktu salah yang luar biasa. Jadi kita perlu menyaring baris ini.
  4. Bergabunglah dengan slot waktu dengan tabel aslinya. && operator memeriksa apakah dua jenis rentang tumpang tindih.
  5. Mengelompokkan berdasarkan slot waktu tunggal, menggabungkan nama dan jumlah. Saring slot waktu hanya dengan satu aktivitas dengan menggunakan HAVING klausa
  6. Agak sulit untuk mendapatkan titik awal dan akhir yang tepat. Jadi titik awal adalah maksimum awal aktivitas atau awal slot waktu (yang dapat diperoleh dengan menggunakan lower ). Misalnya. Ambil slot 20-20:30:Ini dimulai 20 jam tetapi baik B maupun C tidak memiliki titik awal di sana. Mirip dengan waktu akhir.


  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 secara eksplisit melemparkan jenis array literal di sqlalchemy menggunakan postgresql?

  2. Apakah tidak menggunakan NULL di PostgreSQL masih menggunakan bitmap NULL di header?

  3. Objek Besar sialan itu

  4. buat tabel di postgreSQL

  5. cara menghitung saldo di software akuntansi menggunakan fungsi jendela postgres