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

Làm cách nào để tìm tổng số ngày đã sử dụng trong một tháng?

Dữ liệu thử nghiệm :

CREATE TABLE your_table ( usr, start_date, end_date ) AS (
  SELECT 'A', DATE '2017-06-01', DATE '2017-06-03' FROM DUAL UNION ALL
  SELECT 'B', DATE '2017-06-02', DATE '2017-06-04' FROM DUAL UNION ALL -- Overlaps previous
  SELECT 'C', DATE '2017-06-06', DATE '2017-06-06' FROM DUAL UNION ALL
  SELECT 'D', DATE '2017-06-07', DATE '2017-06-07' FROM DUAL UNION ALL -- Adjacent to previous
  SELECT 'E', DATE '2017-06-11', DATE '2017-06-20' FROM DUAL UNION ALL
  SELECT 'F', DATE '2017-06-14', DATE '2017-06-15' FROM DUAL UNION ALL -- Within previous
  SELECT 'G', DATE '2017-06-22', DATE '2017-06-25' FROM DUAL UNION ALL
  SELECT 'H', DATE '2017-06-24', DATE '2017-06-28' FROM DUAL UNION ALL -- Overlaps previous and next
  SELECT 'I', DATE '2017-06-27', DATE '2017-06-30' FROM DUAL UNION ALL
  SELECT 'J', DATE '2017-06-27', DATE '2017-06-28' FROM DUAL;          -- Within H and I          

Truy vấn :

SELECT SUM( days ) AS total_days
FROM   (
  SELECT dt - LAG( dt ) OVER ( ORDER BY dt ) + 1 AS days,
         start_end
  FROM   (
    SELECT dt,
           CASE SUM( value ) OVER ( ORDER BY dt ASC, value DESC, ROWNUM ) * value
             WHEN 1 THEN 'start'
             WHEN 0 THEN 'end'
           END AS start_end
    FROM   your_table
    UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )
  )
  WHERE start_end IS NOT NULL
)
WHERE start_end = 'end';

Đầu ra :

TOTAL_DAYS
----------
        25

Giải thích :

SELECT dt, value
FROM   your_table
UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )

Điều này sẽ UNPIVOT bảng sao cho ngày bắt đầu và ngày kết thúc nằm trong cùng một cột (dt ) và được cung cấp giá trị tương ứng là +1 cho ngày bắt đầu và -1 cho ngày kết thúc.

SELECT dt,
       SUM( value ) OVER ( ORDER BY dt ASC, value DESC, ROWNUM ) AS total,
       value
FROM   your_table
UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )

Sẽ cung cấp ngày bắt đầu và ngày kết thúc và tổng tích lũy của các giá trị được tạo đó. Phần đầu của một dải ô sẽ luôn có value=1total=1 và phần cuối của một dải ô sẽ luôn có total=0 . Nếu một ngày ở giữa một phạm vi thì ngày đó sẽ có total>1 hoặc value=-1total=1 . Sử dụng điều này, nếu bạn nhân valuetotal thì đầu của một phạm vi là khi value*total=1 và phần cuối của một dải ô là khi value*total=0 và bất kỳ giá trị nào khác cho biết một ngày đang ở giữa một phạm vi.

Đó là những gì điều này mang lại:

SELECT dt,
       CASE SUM( value ) OVER ( ORDER BY dt ASC, value DESC, ROWNUM ) * value
         WHEN 1 THEN 'start'
         WHEN 0 THEN 'end'
       END AS start_end
FROM   your_table
UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )

Sau đó, bạn có thể lọc ra các ngày khi start_endNULL sẽ để lại cho bạn một bảng có start xen kẽ và end hàng mà bạn có thể sử dụng LAG để tính toán số ngày chênh lệch:

SELECT dt - LAG( dt ) OVER ( ORDER BY dt ) + 1 AS days,
       start_end
FROM   (
  SELECT dt,
         CASE SUM( value ) OVER ( ORDER BY dt ASC, value DESC, ROWNUM ) * value
           WHEN 1 THEN 'start'
           WHEN 0 THEN 'end'
         END AS start_end
  FROM   your_table
  UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )
)
WHERE start_end IS NOT NULL

Tất cả những gì bạn cần làm sau đó là SUM tất cả sự khác biệt cho end - start; đưa ra truy vấn ở trên.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ORA-00905:thiếu tiên tri lỗi từ khóa

  2. truy vấn oracle chậm với REGEXP_SUBSTR (AGGREGATOR, '[^;] +', 1, LEVEL)

  3. Tự tham gia vào oracle với các ví dụ

  4. Thủ tục lưu trữ Oracle:trả về cả tham số đặt và ra kết quả

  5. Oracle Thêm 1 giờ trong SQL