Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Bagaimana melakukan jumlah bergulir, setiap baris harus menyertakan jumlah baris sebelumnya

Anda dapat menggunakan variabel pengguna MySQL untuk meniru fungsi analitik. (Ada beberapa pendekatan lain juga, seperti menggunakan semi-join atau menggunakan subquery yang berkorelasi. Saya dapat memberikan solusi untuk itu juga, jika Anda merasa itu mungkin lebih tepat.)

Untuk meniru fungsi analitik "total berjalan", coba sesuatu seperti ini:

SELECT t.user_id
     , t.starttime
     , t.order_number
     , IF(t.order_number IS NOT NULL,
         @tot_dur := 0,
         @tot_dur := @tot_dur + t.visit_duration_seconds) AS tot_dur
  FROM visit t
  JOIN (SELECT @tot_dur := 0) d
 ORDER BY t.user_id, t.start_time

"Trik" di sini adalah menggunakan fungsi IF untuk menguji apakah order_number adalah nol. Jika nol, kami menambahkan nilai durasi ke variabel, jika tidak, kami menyetel variabel ke nol.

Kami menggunakan tampilan sebaris (alias sebagai d , untuk memastikan bahwa variabel @tot_dur diinisialisasi ke nol.

CATATAN:Berhati-hatilah dengan menggunakan variabel pengguna MySQL seperti ini. Dalam pernyataan SELECT seperti di atas, penetapan variabel dalam daftar SELECT terjadi setelah ORDER BY, sehingga kita bisa mendapatkan perilaku deterministik.

Kueri itu tidak menangani "jeda" di user_id. Untuk mendapatkannya, kita akan membutuhkan nilai user_id dari baris sebelumnya. Kita dapat mempertahankannya di variabel pengguna lain. Urutan operasi bersifat deterministik, dan kita perlu berhati-hati untuk melakukan akumulasi SEBELUM kita menimpa user_id dari baris sebelumnya.

Kita juga perlu menyusun ulang kolom sehingga user_id muncul setelah tot_dur (atau menyertakan salinan kedua kolom user_id)

SELECT t.user_id
     , t.starttime
     , t.order_number
     , IF(t.order_number IS NULL,
         @tot_dur := IF(@prev_user_id = t.user_id,@tot_dur,0) + t.visit_duration_seconds,
         @tot_dur := 0
       ) AS tot_dur
     , @prev_user_id := t.user_id AS prev_user_id
  FROM visit t
  JOIN (SELECT @tot_dur := 0, @prev_user_id := NULL) d
 ORDER BY t.user_id, t.start_time

Nilai yang dikembalikan dalam user_id dan prev_user_id kolom adalah identik. Kolom "ekstra" tersebut dapat dihapus, atau kolom dapat disusun ulang dengan membungkus kueri (sebagai tampilan sebaris) dalam kueri lain, meskipun hal ini memerlukan biaya kinerja:

SELECT v.user_id
     , v.starttime
     , v.order_number
     , v.tot_dur
  FROM (SELECT t.starttime
             , t.order_number
             , IF(t.order_number IS NULL,
                 @tot_dur := IF(@prev_user_id = t.user_id,@tot_dur,0) + t.visit_duration_seconds,
                 @tot_dur := 0
               ) AS tot_dur
             , @prev_user_id := t.user_id AS user_id
          FROM visit t
          JOIN (SELECT @tot_dur := 0, @prev_user_id := NULL) d
         ORDER BY t.user_id, t.start_time
       ) v

Kueri itu menunjukkan bahwa MySQL dapat mengembalikan hasil yang ditentukan. Namun untuk kinerja optimal, kami hanya ingin menjalankan kueri dalam tampilan sebaris (alias sebagai v ), dan menangani pengurutan ulang kolom (menempatkan kolom user_id terlebih dahulu) di sisi klien, saat baris diambil.

Dua pendekatan umum lainnya menggunakan semi-join, dan menggunakan subquery yang berkorelasi, meskipun pendekatan ini bisa lebih intensif sumber daya saat memproses set besar.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL menghitung semua baris alih-alih menghitung baris individual

  2. Bagaimana cara mereferensikan atribut di dalam tabel ke nilai di dalam baris baru di dalam tabel yang sama?

  3. PERINGATAN:Membuat koneksi SSL tanpa verifikasi identitas server tidak disarankan

  4. Perbedaan antara database MySQL/SQLite/etc?

  5. HAPUS menggunakan LEFT JOIN dengan LIMIT di MySQL