Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Oracle SQL - Pilih pengguna antara dua tanggal per bulan

Kueri ini menunjukkan jumlah pengguna aktif yang efektif per akhir bulan.

Cara kerjanya:

  1. Konversikan setiap baris input (dengan StartDate dan EndDate nilai) menjadi dua baris yang mewakili titik waktu saat jumlah pengguna aktif bertambah (pada StartDate ) dan dikurangi (pada EndDate ). Kita perlu mengonversi NULL ke nilai tanggal yang jauh karena NULL nilai diurutkan sebelum bukan setelah non-NULL nilai:

    Ini membuat data Anda terlihat seperti ini:

    OnThisDate   Change
    2018-01-01        1
    2019-01-01       -1
    2018-01-01        1
    9999-12-31       -1
    2019-01-01        1
    2019-06-01       -1
    2017-01-01        1
    2019-03-01       -1
    
  2. Kemudian kita cukup SUM OVER Change nilai (setelah diurutkan) untuk mendapatkan jumlah pengguna aktif pada tanggal tertentu:

    Jadi pertama, urutkan berdasarkan OnThisDate :

    OnThisDate   Change
    2017-01-01        1
    2018-01-01        1
    2018-01-01        1
    2019-01-01        1
    2019-01-01       -1
    2019-03-01       -1
    2019-06-01       -1
    9999-12-31       -1
    

    Kemudian SUM OVER :

    OnThisDate   ActiveCount
    2017-01-01             1
    2018-01-01             2
    2018-01-01             3
    2019-01-01             4
    2019-01-01             3
    2019-03-01             2
    2019-06-01             1
    9999-12-31             0
    
  3. Kemudian kita PARTITION (bukan mengelompokkan!) baris berdasarkan bulan dan mengurutkannya berdasarkan tanggalnya sehingga kami dapat mengidentifikasi ActiveCount terakhir baris untuk bulan itu (ini sebenarnya terjadi di WHERE dari kueri terluar, menggunakan ROW_NUMBER() dan COUNT() untuk setiap bulan PARTITION ):

    OnThisDate   ActiveCount    IsLastInMonth
    2017-01-01             1                1
    2018-01-01             2                0
    2018-01-01             3                1
    2019-01-01             4                0
    2019-01-01             3                1
    2019-03-01             2                1
    2019-06-01             1                1
    9999-12-31             0                1
    
  4. Kemudian filter di mana IsLastInMonth = 1 (sebenarnya, di mana ROW_COUNT() = COUNT(*) di dalam setiap PARTITION ) untuk memberi kami data keluaran akhir:

    At-end-of-month     Active-count
    2017-01                        1
    2018-01                        3
    2019-01                        3
    2019-03                        2
    2019-06                        1
    9999-12                        0
    

Hal ini menyebabkan "kesenjangan" dalam kumpulan hasil karena At-end-of-month kolom hanya menampilkan baris di mana Active-count nilai sebenarnya berubah daripada memasukkan semua bulan kalender yang mungkin - tetapi itu ideal (sejauh yang saya ketahui) karena tidak termasuk data yang berlebihan. Mengisi celah dapat dilakukan di dalam kode aplikasi Anda hanya dengan mengulangi baris keluaran untuk setiap bulan tambahan hingga mencapai At-end-of-month berikutnya nilai.

Inilah kueri menggunakan T-SQL di SQL Server (Saya tidak memiliki akses ke Oracle sekarang). Dan inilah SQLFiddle yang saya gunakan untuk menemukan solusi:http://sqlfiddle.com/# !18/ad68b7/24

SELECT
  OtdYear,
  OtdMonth,
  ActiveCount
FROM
  (

    -- This query adds columns to indicate which row is the last-row-in-month ( where RowInMonth == RowsInMonth )
    SELECT
      OnThisDate,
      OtdYear,
      OtdMonth,
      ROW_NUMBER() OVER ( PARTITION BY OtdYear, OtdMonth ORDER BY OnThisDate ) AS RowInMonth,
      COUNT(*) OVER ( PARTITION BY OtdYear, OtdMonth ) AS RowsInMonth,
      ActiveCount
    FROM
      (
        SELECT
          OnThisDate,
          YEAR( OnThisDate ) AS OtdYear,
          MONTH( OnThisDate ) AS OtdMonth,
          SUM( [Change] ) OVER ( ORDER BY OnThisDate ASC ) AS ActiveCount
        FROM
          (
            SELECT
              StartDate AS [OnThisDate],
              1 AS [Change]
            FROM
              tbl

            UNION ALL

            SELECT
              ISNULL( EndDate, DATEFROMPARTS( 9999, 12, 31 ) ) AS [OnThisDate],
              -1 AS [Change]
            FROM
              tbl
          ) AS sq1
      ) AS sq2
  ) AS sq3
WHERE
  RowInMonth = RowsInMonth
ORDER BY
  OtdYear,
  OtdMonth

Kueri ini bisa diratakan menjadi lebih sedikit kueri bersarang dengan menggunakan fungsi agregat dan jendela secara langsung daripada menggunakan alias (seperti OtdYear , ActiveCount , dll) tetapi itu akan membuat kueri lebih sulit untuk dipahami.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. di mana saya harus meletakkan sumber daya penginstal (file wxs, skrip dmg, ikon) dan cara mengonfigurasi maven antrun saat menggunakan aplikasi mandiri

  2. Metode Pengumpulan:Fungsi COUNT Dalam Database Oracle

  3. Oracle REF tidak dapat melalui

  4. Dapatkan BLOB dari Kolom BFILE di Oracle

  5. Memprediksi data deret waktu di Oracle/SQL