Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Menemukan acara simultan dalam database antara waktu

Penafian:Saya menulis jawaban saya berdasarkan (sangat baik) posting berikut:

https://www.itprotoday.com/sql-server/calculating-concurrent-sessions-part-3 (Part1 dan 2 juga direkomendasikan)

Hal pertama yang harus dipahami di sini dengan masalah itu adalah bahwa sebagian besar solusi saat ini yang ditemukan di internet pada dasarnya dapat memiliki dua masalah

  • Hasilnya bukan jawaban yang benar (misalnya jika rentang A tumpang tindih dengan B dan C tetapi B tidak tumpang tindih dengan C, mereka dihitung sebagai 3 rentang yang tumpang tindih).
  • Cara menghitungnya sangat tidak efisien (karena O(n^2) dan / atau mereka berputar setiap detik dalam periode tersebut)

Masalah kinerja umum dalam solusi seperti yang diusulkan oleh Unreasons adalah solusi kuadratis, untuk setiap panggilan Anda perlu memeriksa semua panggilan lain jika tumpang tindih.

ada solusi umum linier algoritmik yaitu daftar semua "acara" (mulai panggilan dan akhiri panggilan) yang diurutkan berdasarkan tanggal, dan tambahkan 1 untuk memulai dan kurangi 1 untuk hang-up, dan ingat maks. Itu dapat diimplementasikan dengan mudah dengan kursor (solusi yang diusulkan oleh Hafhor tampaknya seperti itu) tetapi kursor bukanlah cara yang paling efisien untuk menyelesaikan masalah.

Artikel yang dirujuk memiliki contoh luar biasa, solusi berbeda, perbandingan kinerjanya. Solusi yang diusulkan adalah:

WITH C1 AS
(
  SELECT starttime AS ts, +1 AS TYPE,
    ROW_NUMBER() OVER(ORDER BY starttime) AS start_ordinal
  FROM Calls

  UNION ALL

  SELECT endtime, -1, NULL
  FROM Calls
),
C2 AS
(
  SELECT *,
    ROW_NUMBER() OVER(  ORDER BY ts, TYPE) AS start_or_end_ordinal
  FROM C1
)
SELECT MAX(2 * start_ordinal - start_or_end_ordinal) AS mx
FROM C2
WHERE TYPE = 1

Penjelasan

misalkan kumpulan data ini

+-------------------------+-------------------------+
|        starttime        |         endtime         |
+-------------------------+-------------------------+
| 2009-01-01 00:02:10.000 | 2009-01-01 00:05:24.000 |
| 2009-01-01 00:02:19.000 | 2009-01-01 00:02:35.000 |
| 2009-01-01 00:02:57.000 | 2009-01-01 00:04:04.000 |
| 2009-01-01 00:04:12.000 | 2009-01-01 00:04:52.000 |
+-------------------------+-------------------------+

Ini adalah cara untuk menerapkan ide yang sama dengan kueri, menambahkan 1 untuk setiap awal panggilan dan mengurangi 1 untuk setiap akhir.

  SELECT starttime AS ts, +1 AS TYPE,
    ROW_NUMBER() OVER(ORDER BY starttime) AS start_ordinal
  FROM Calls

bagian C1 CTE ini akan menerima setiap waktu mulai dari setiap panggilan dan nomornya

+-------------------------+------+---------------+
|           ts            | TYPE | start_ordinal |
+-------------------------+------+---------------+
| 2009-01-01 00:02:10.000 |    1 |             1 |
| 2009-01-01 00:02:19.000 |    1 |             2 |
| 2009-01-01 00:02:57.000 |    1 |             3 |
| 2009-01-01 00:04:12.000 |    1 |             4 |
+-------------------------+------+---------------+

Sekarang kode ini

  SELECT endtime, -1, NULL
  FROM Calls

Akan menghasilkan semua "waktu berakhir" tanpa penomoran baris

+-------------------------+----+------+
|         endtime         |    |      |
+-------------------------+----+------+
| 2009-01-01 00:02:35.000 | -1 | NULL |
| 2009-01-01 00:04:04.000 | -1 | NULL |
| 2009-01-01 00:04:52.000 | -1 | NULL |
| 2009-01-01 00:05:24.000 | -1 | NULL |
+-------------------------+----+------+

Sekarang membuat UNION memiliki definisi C1 CTE lengkap, Anda akan memiliki kedua tabel yang tercampur

+-------------------------+------+---------------+
|           ts            | TYPE | start_ordinal |
+-------------------------+------+---------------+
| 2009-01-01 00:02:10.000 |    1 |             1 |
| 2009-01-01 00:02:19.000 |    1 |             2 |
| 2009-01-01 00:02:57.000 |    1 |             3 |
| 2009-01-01 00:04:12.000 |    1 |             4 |
| 2009-01-01 00:02:35.000 | -1   |     NULL      |
| 2009-01-01 00:04:04.000 | -1   |     NULL      |
| 2009-01-01 00:04:52.000 | -1   |     NULL      |
| 2009-01-01 00:05:24.000 | -1   |     NULL      |
+-------------------------+------+---------------+

C2 dihitung pengurutan dan penomoran C1 dengan kolom baru

C2 AS
(
  SELECT *,
    ROW_NUMBER() OVER(  ORDER BY ts, TYPE) AS start_or_end_ordinal
  FROM C1
)

+-------------------------+------+-------+--------------+
|           ts            | TYPE | start | start_or_end |
+-------------------------+------+-------+--------------+
| 2009-01-01 00:02:10.000 |    1 | 1     |            1 |
| 2009-01-01 00:02:19.000 |    1 | 2     |            2 |
| 2009-01-01 00:02:35.000 |   -1 | NULL  |            3 |
| 2009-01-01 00:02:57.000 |    1 | 3     |            4 |
| 2009-01-01 00:04:04.000 |   -1 | NULL  |            5 |
| 2009-01-01 00:04:12.000 |    1 | 4     |            6 |
| 2009-01-01 00:04:52.000 |   -1 | NULL  |            7 |
| 2009-01-01 00:05:24.000 |   -1 | NULL  |            8 |
+-------------------------+------+-------+--------------+

Dan di sanalah keajaiban terjadi, setiap saat hasil dari #start - #ends adalah jumlah panggilan bersamaan saat ini.

untuk setiap Jenis =1 (mulai acara) kami memiliki nilai #start di kolom ke-3. dan kami juga memiliki #start + #end (di kolom ke-4)

#start_or_end = #start + #end

#end = (#start_or_end - #start)

#start - #end = #start - (#start_or_end - #start)

#start - #end = 2 * #start - #start_or_end

jadi di SQL:

SELECT MAX(2 * start_ordinal - start_or_end_ordinal) AS mx
FROM C2
WHERE TYPE = 1

Dalam hal ini dengan rangkaian panggilan yang diusulkan, hasilnya adalah 2.

Dalam artikel yang diusulkan, ada sedikit perbaikan untuk memiliki hasil yang dikelompokkan misalnya layanan atau "perusahaan telepon" atau "pusat telepon" dan ide ini juga dapat digunakan untuk mengelompokkan misalnya berdasarkan slot waktu dan memiliki konkurensi maksimum jam demi jam dalam hari tertentu.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. 7645 Null atau predikat teks lengkap kosong

  2. SQL WHERE.. IN klausa beberapa kolom

  3. Hasil Query Email sebagai Tabel HTML di SQL Server (T-SQL)

  4. Tidak dapat menemukan prosedur tersimpan 'dbo.aspnet_CheckSchemaVersion'

  5. 3 Area yang Akan Diuntungkan dari Menggunakan Alat Pemantauan Kinerja SQL Server