使用函数和条件生成另外两列

时间:2013-03-07 07:19:54

标签: sql oracle

输入表:

store    | employee  | date             |  timein  | timeout |   
    1    |      A    |        1-jan-12  |  10:00   | 17:00   |
    1    |      A    |        1-jan-12  |  20:00   | 22:00   |
    2    |      B    |        1-jan-12  |  10:00   |  -      |
    2    |      B    |        1-jan-12  |  17:00   | 20:00   |
    2    |      B    |        2-jan-12  |  10:00   | 17:00   |
    3    |      C    |        1-jan-12  |  10:00   | 12:00   |
    3    |      C    |        1-jan-12  |  13:00   | 15:00   |
    3    |      C    |        1-jan-12  |  20:00   | 23:00   |

所需的输出:

store | employee | date      |  timein  | timeout | hours | working_days |
 1    |     A    | 1-jan-12  |  10:00   | 17:00   |   7   |              |
 1    |     A    | 1-jan-12  |  20:00   | 22:00   |   2   |        1     |
 2    |     B    | 1-jan-12  |  10:00   |  -      |   0   |              | 
 2    |     B    | 1-jan-12  |  17:00   | 20:00   |   5   |        0     | 
 2    |     B    | 2-jan-12  |  10:00   | 17:00   |   7   |        1     | 
 3    |     C    | 1-jan-12  |  10:00   | 12:00   |   2   |              | 
 3    |     C    | 1-jan-12  |  13:00   | 15:00   |   2   |              | 
 3    |     C    | 1-jan-12  |  20:00   | 23:00   |   3   |        1     |

我的查询是:

select 
      store, 
      employee,
      date,
      timein,
      timeout,
      cast(trim(trailing ':' from cast(timeout) as number)-trim(trailing ':' from cast(timein) as number) as number) as hours,
     case
      when timeout is null then 0 and
     end
from
      tableattend
where date between '1-jan-12' and '2-jan-12' and store between 'A' and 'C'

working_days 字段将以这种方式显示,但无法获得创建上述结果的确切功能。请指导我。

3 个答案:

答案 0 :(得分:0)

您在提交中声明了生成WORKING_DAYS的规则:

  • 如果记录不是DATE的最后一条记录,那么 NULL
  • 如果记录是DATE的最后一条记录,但TIMEOUT为空则 0
  • 其他 1

这是查询的简化版本,解决了具体问题:

select date
       , timein 
       , timeout
       , case 
            when rn != 1 then null
            when timeout is null then 0
            else 1
          end as working_days
from ( select date
              , timein 
              , timeout
              , row_number() over partition by date order by timein desc ) rn
       from  tableattend
      where date between '1-jan-12' and '2-jan-12' 
      and store between 'A' and 'C' )
order by date, timein

答案 1 :(得分:0)

APC的回答略有不同,因为我对工作日规则的解释略有不同......这给出了您的预期输出。但似乎不符合你所说的规则:

select store, employee, dt, timein, timeout, hours,
    case when rn = 1 then decode(tmp_timeout, null, 0, 1) end as working_days
from (
    select store, employee, dt, timein, timeout,
          case when timeout is null then 0
          else extract (hour from to_dsinterval('0 ' || timeout || ':00')
              - to_dsinterval('0 ' || timein || ':00'))
          end as hours,
          first_value(timeout)
              over (partition by store, employee, dt
                  order by timeout nulls first) as tmp_timeout,
          row_number()
              over (partition by store, employee, dt
                  order by timein desc) as rn
    from tableattend
)
where dt between '1-jan-12' and '2-jan-12'
-- and store between 'A' and 'C' -- store is numeric??
/

我调用日期列dt来避免使用保留字,但尝试匹配您提供的字。

     STORE EMPLOYEE DT        TIMEIN TIMEOUT      HOURS WORKING_DAYS
---------- -------- --------- ------ ------- ---------- ------------
         1 A        01-JAN-12 10:00  17:00            7              
         1 A        01-JAN-12 20:00  22:00            2            1 
         2 B        01-JAN-12 10:00                   0              
         2 B        01-JAN-12 17:00  20:00            3            0 
         2 B        02-JAN-12 10:00  17:00            7            1 
         3 C        01-JAN-12 10:00  12:00            2              
         3 C        01-JAN-12 13:00  15:00            2              
         3 C        01-JAN-12 20:00  23:00            3            1 

如果您将时间作为完整日期存储而不是作为单独的(varchar2)列存储,则会更容易。目前尚不清楚如果有人在午夜过夜会发生什么或应该发生什么,所以timeout似乎会出现在timein之前。

答案 2 :(得分:0)

关于如何减去时间部分以获得小时的几个例子,如上例所示。不清楚你是如何得到工作日的。我认为您可以将工作时间除以8以获得工作日...所有示例都经过测试:

SELECT round((time_diff/3600)/24, 1) days
     , trunc(time_diff/3600) hrs
     , trunc(mod(time_diff, 3600) / 60) mnt
     , trunc(mod(time_diff, 3600) / 60 /60) sec
  FROM
  (
   SELECT time_in, time_out, (time_out-time_in)* 86400 time_diff
     FROM 
   (
    SELECT to_date('01-JAN-2012 17:00:00', 'DD-MON-YYYY HH24:MI:SS') time_out
         , to_date('01-JAN-2012 10:00:00', 'DD-MON-YYYY HH24:MI:SS') time_in
      FROM dual
   ))
   /

使用提取示例:

 Select time_in, time_out, time_diff,
        EXTRACT(DAY FROM time_diff) days,
        EXTRACT(HOUR FROM time_diff) hours,
        EXTRACT(MINUTE FROM time_diff) minutes,
        EXTRACT(SECOND FROM time_diff) seconds
   From
   (
    Select time_in, time_out, (time_out - time_in) time_diff
      From
     (
      Select CAST(to_date('01-JAN-2012 17:00:00', 'DD-MON-YYYY HH24:MI:SS') AS TIMESTAMP) time_out
           , CAST(to_date('01-JAN-2012 10:00:00', 'DD-MON-YYYY HH24:MI:SS') AS TIMESTAMP) time_in
         From dual
    ))
  /