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.