Tuyên bố từ chối trách nhiệm:Tôi đang viết câu trả lời của mình dựa trên (excelent) bài đăng sau:
https://www.itprotoday.com/sql-server/calculating-concurrent-sessions-part-3 (Phần 1 và 2 cũng được đề xuất)
Điều đầu tiên cần hiểu ở đây với vấn đề đó là hầu hết các giải pháp hiện tại được tìm thấy trên internet có thể có hai vấn đề về cơ bản
- Kết quả không phải là câu trả lời chính xác (ví dụ:nếu phạm vi A trùng với B và C nhưng B không trùng với C thì được tính là 3 phạm vi trùng nhau).
- Cách tính giá trị này rất kém hiệu quả (vì là O (n ^ 2) và / hoặc chúng đóng vảy cho mỗi giây trong khoảng thời gian)
Vấn đề hiệu suất phổ biến trong các giải pháp như giải pháp do Unreasons đề xuất là một giải pháp lập phương, đối với mỗi cuộc gọi, bạn cần kiểm tra tất cả các lệnh gọi khác xem chúng có bị chồng chéo hay không.
có một giải pháp chung tuyến tính mật mã là liệt kê tất cả các "sự kiện" (bắt đầu cuộc gọi và kết thúc cuộc gọi) được sắp xếp theo ngày và thêm 1 cho một bắt đầu và trừ 1 cho một lần treo máy và nhớ giá trị tối đa. Điều đó có thể được thực hiện dễ dàng với con trỏ (giải pháp do Hafhor đề xuất dường như là theo cách đó) nhưng con trỏ không phải là cách hiệu quả nhất để giải quyết vấn đề.
Bài viết tham khảo có các ví dụ xuất sắc, các giải pháp khác nhau, so sánh hiệu suất của chúng. Giải pháp được đề xuất là:
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
Giải thích
giả sử tập hợp dữ liệu này
+-------------------------+-------------------------+
| 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 |
+-------------------------+-------------------------+
Đây là một cách để triển khai với một truy vấn có cùng ý tưởng, thêm 1 cho mỗi lần bắt đầu cuộc gọi và trừ 1 cho mỗi phần cuối.
SELECT starttime AS ts, +1 AS TYPE,
ROW_NUMBER() OVER(ORDER BY starttime) AS start_ordinal
FROM Calls
phần này của C1 CTE sẽ lấy mỗi thời gian bắt đầu của mỗi cuộc gọi và đánh số cho nó
+-------------------------+------+---------------+
| 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 |
+-------------------------+------+---------------+
Bây giờ là mã này
SELECT endtime, -1, NULL
FROM Calls
Sẽ tạo tất cả "thời gian kết thúc" mà không đánh số hàng
+-------------------------+----+------+
| 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 |
+-------------------------+----+------+
Bây giờ làm cho UNION để có định nghĩa CTE C1 đầy đủ, bạn sẽ có cả hai bảng trộn lẫn
+-------------------------+------+---------------+
| 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 được tính toán sắp xếp và đánh số C1 với một cột mới
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 |
+-------------------------+------+-------+--------------+
Và ở đó điều kỳ diệu xảy ra, bất kỳ lúc nào kết quả của #start - #ends là số lượng cuộc gọi đồng dòng tại thời điểm này.
đối với mỗi Loại =1 (sự kiện bắt đầu), chúng ta có giá trị #start trong cột thứ 3. và chúng tôi cũng có #start + #end (trong cột thứ 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
vì vậy trong SQL:
SELECT MAX(2 * start_ordinal - start_or_end_ordinal) AS mx
FROM C2
WHERE TYPE = 1
Trong trường hợp này với nhóm lệnh gọi prposed, kết quả là 2.
Trong bài viết được đề xuất, có một chút ngẫu hứng để có một kết quả được nhóm lại theo ví dụ:một dịch vụ hoặc "công ty điện thoại" hoặc "trung tâm điện thoại" và ý tưởng này cũng có thể được sử dụng để nhóm ví dụ theo khoảng thời gian và có mức đồng thời tối đa từng giờ trong một ngày nhất định.