【问题标题】:Create timesheet table by select query in Oracle在 Oracle 中通过 select 查询创建时间表表
【发布时间】:2017-08-29 04:52:00
【问题描述】:

我有一个这种形式的表格(这只是部分视图,表格包含更多列):

| USER     | date_of        | duration |  
|----------|----------------|----------|  
| John     |   01.08.2017   |   5      |  
| Anna     |   01.08.2017   |   6      |  
| John     |   03.08.2017   |   10     |      
| Anna     |   05.08.2017   |   7      |     
| Eugene   |   30.08.2017   |   16     | 

我需要一个查询(选择),它将以以下形式返回数据:

|USER    | 01| 02| 03| 04| 05| 06| ... | 29| 30| 31|Total|Count| 
|--------|---|---|---|---|---|---|-----|---|---|---|-----|-----|  
|Anna    |  6|   |   |   |  7|   |     |   |   |   |  13 |   2 |  
|John    |  5|   | 10|   |   |   |     |   |   |   |  15 |   1 |  
|Eugene  |   |   |   |   |   |   |     |   | 16|   |  16 |   1 |  

因此,我需要在 01..31 列(一个月中的某天,2 月 28/29 日,8 月 31 日等)中填写时间表,在空天时为空,计算每个时间的总和“总计”列中的用户并将持续时间超过 5 天的天数计入“计数”列。 在完整版中,查询会复杂得多,但现在我需要从上面描述的开始。

【问题讨论】:

标签: sql oracle select


【解决方案1】:

这听起来像 PIVOT,但您还需要一些聚合。这可以通过 GROUP BY ROLLUP 或其他类似的聚合扩展来完成,尽管它更复杂,因为您需要 TOTAL 和 条件 COUNT。

使用“手动”旋转一切都很简单(但很乏味)——在 Oracle 11.1 中引入 PIVOT 运算符之前,每个人都必须这样做。这样做的好处是它可以在早期版本中运行,而且 - 虽然还有更多内容要编写 - 如果需要,将来更容易修改。

with
     inputs ( usr, date_of, duration ) as ( 
       select 'John'  , to_date('01.08.2017', 'dd.mm.yyyy'),  5 from dual union all
       select 'Ann'   , to_date('01.08.2017', 'dd.mm.yyyy'),  6 from dual union all
       select 'John'  , to_date('03.08.2017', 'dd.mm.yyyy'), 10 from dual union all
       select 'Ann'   , to_date('05.08.2017', 'dd.mm.yyyy'),  7 from dual union all
       select 'Eugene', to_date('30.08.2017', 'dd.mm.yyyy'), 16 from dual
     )
-- End of simulated data (for testing only, not part of the solution).
-- Use your own table and column names in the SQL query below.
select   usr,
         sum(case extract(day from date_of) when  1 then duration end) as "01",
         sum(case extract(day from date_of) when  2 then duration end) as "02",
         sum(case extract(day from date_of) when  3 then duration end) as "03",
 --        .............
 --        .............
         sum(case extract(day from date_of) when 31 then duration end) as "31",
         sum(duration) as total_duration,
         count(case when duration > 5 then 1 end) as cnt
from     inputs
group by usr
;

部分输出(图中到目前为止包含的列):

USR     01  02  03  31  TOTAL_DURATION  CNT
------  --  --  --  --  --------------  ---
John     5      10                  15    1
Eugene                              16    1
Ann      6                          13    2

USER 和 COUNT 是保留字,不要在输入和输出中将它们用作列名。最好不要使用双引号的列名(这意味着不应使用01 等作为列名)。

【讨论】:

  • 正是我需要的!非常感谢!
  • @SergeySytnik 注意:假设所有日期都在 2017 年 8 月。如果不是,您将开始混合不同月份的值。为避免这种情况,请添加 WHERE 条件以确保在其余查询中仅考虑 2017 年 8 月的日期。
  • 我明白了。谢谢你。在我的情况下,输入表总是过滤到一个月
猜你喜欢
  • 1970-01-01
  • 2019-08-25
  • 1970-01-01
  • 1970-01-01
  • 2021-10-19
  • 1970-01-01
  • 2019-12-26
  • 1970-01-01
  • 2019-03-14
相关资源
最近更新 更多