Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Tìm các sự kiện đồng thời trong cơ sở dữ liệu giữa các thời điểm

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.



  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 Server là gì? (Định nghĩa, Phiên bản, Phiên bản)

  2. SQL Server 2016:Trình thiết kế truy vấn

  3. Cách lấy danh sách Ràng buộc khóa chính từ tất cả cơ sở dữ liệu trên Phiên bản SQL Server - Hướng dẫn SQL Server / TSQL Phần 60

  4. Cách tạo ràng buộc khóa ngoại với tùy chọn ON DELETE SET NULL trong SQL Server - Hướng dẫn sử dụng SQL Server / TSQL Phần 81

  5. Quyền THỰC HIỆN đã bị từ chối trên đối tượng 'xxxxxxx', cơ sở dữ liệu 'zzzzzzz', giản đồ 'dbo'