sql - 如何找到一个月中使用的总天数?

标签 sql oracle

我得到了一个月内使用服务的总天数。
(Start_Date 和 End_Date 是 - 都包括在内)

示例数据 1:

User  Start_Date     End_Date
A     01-Jun-2017    30-Jun-2017
B     06-Jun-2017    30-Jun-2017

答:服务使用天数 = 30 天。

样本数据 2:
User  Start_Date     End_Date
C     06-Jun-2017    10-Jun-2017
D     02-Jun-2017    02-Jun-2017

答:服务使用天数 = 6 天。

如何编写代码以在 SQL 中找到相同的、更可取的 PLSQL。

最佳答案

测试数据 :

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          

查询 :
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';

输出 :
TOTAL_DAYS
----------
        25

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

这将 UNPIVOT表中的开始日期和结束日期位于同一列 ( dt ) 中,并为开始日期指定相应的值 +1,结束日期指定为 -1。
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 ) )

将给出开始和结束日期以及这些生成值的累积总和。范围的开头总是 value=1total=1并且范围的结尾总是有 total=0 .如果日期在一个范围的中间,那么它要么是 total>1value=-1total=1 .使用这个,如果你乘以 valuetotal那么范围的开始是 value*total=1范围的结尾是 value*total=0和任何其他值表示一个范围中途的日期。

这就是它给出的:
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 ) )

然后您可以过滤掉 start_end 的日期。是 NULL这将为您留下一张交替使用的 table startend您可以使用的行 LAG计算天数差异:
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

您需要做的就是SUM end - start 的所有差异;这给出了上面的查询。

关于sql - 如何找到一个月中使用的总天数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44705646/

相关文章:

sql - 在每一列上选择替换

sql - 逐日选择

oracle - 如果集合为空,FETCH INTO 不会引发异常,不是吗?

.net - 在不同的模式中引用相同的表名

oracle - PL/SQL - 在管道函数中立即执行

c++ - Oracle 12. occi c++ "select for update"的最长持续时间

java - 用于sql分析的正则表达式

sql - sql Developer 中的自动跟踪

mysql - 比较 MSSQL 中的表并获得不同的值

sql - 如何从oracle服务器的分区表中获取分区列名