如何在Oracle中将周数转换为日期范围?

时间:2017-09-27 06:52:46

标签: oracle

在Oracle中,我们从以下查询获得周数:

select to_char(TO_DATE(SYSDATE,'DD-MM-YY'),'IW') from dual

我希望得到给定周数的日期范围,例如,周数:1日期范​​围是01-01-2017到08-01-2017。

有没有办法获得给定周数的日期范围?

5 个答案:

答案 0 :(得分:4)

  

“周数:1日期范​​围是01-01-2017至08-01-2017”

不,不是。您将KeyPress(运行MON - SUN)与'IW'混淆,该'WW'从一年的第一天开始运行:

SQL> with dts as (
  2       select date '2017-01-01' + (level-1) as dt
  3       from dual
  4       connect by level <= 8
  5  )
  6  select dt
  7         , to_char(dt, 'DY') as dy_dt
  8         , to_char(dt, 'IW') as iw_dt
  9         , to_char(dt, 'WW') as ww_dt
 10  from dts
 11  order by 1;

DT        DY_DT        IW WW
--------- ------------ -- --
01-JAN-17 SUN          52 01
02-JAN-17 MON          01 01
03-JAN-17 TUE          01 01
04-JAN-17 WED          01 01
05-JAN-17 THU          01 01
06-JAN-17 FRI          01 01
07-JAN-17 SAT          01 01
08-JAN-17 SUN          01 02

8 rows selected.

SQL> 

但是,为IW周数生成一个范围很容易。您需要将IW数字乘以7,您可以将其转换为具有年份日期掩码的日期。然后,您可以使用next_day()函数获取上一个星期一和相对于该日期的下一个星期日:

SQL> with tgt as (
  2      select to_date( &iw *7, 'DDD') as dt from dual
  3      )
  4  select next_day(dt-8, 'mon') as start_date
  5         , next_day(dt, 'sun') as end_date
  6* from tgt;
Enter value for iw: 23
old   2:     select to_date( &iw *7, 'DDD') as dt from dual
new   2:     select to_date( 23 *7, 'DDD') as dt from dual

START_DAT END_DATE
--------- ---------
05-JUN-17 11-JUN-17

SQL> 

很明显,此解决方案使用我的NLS设置(英语):如果您使用不同的设置,则可能需要调整解决方案。

答案 1 :(得分:2)

使用calendar tables很容易解决这些问题。

以下查询建立在假设(ISO 8601)的基础上,即1月4日出现在一年的第一周。因此,我可以通过构建1月4日来生成任何一年第一周的有效日期:to_date(year || '-01-04', 'yyyy-mm-dd')。对于使用to_char(date, 'D')的任何日期,Oracle会告诉我星期几(sun = 1,sat = 7)。 2017年1月4日恰好是周三(第4天)。减去3天将给我一年中第一周的第一天(星期日)。 现在,只需每周增加7天(不包括第一周),就可以轻松找到一年中任何一周的开始日。

with weeks as(
   select 2017 as year, 39 as week from dual union all
   select 2017 as year, 40 as week from dual union all
   select 2018 as year, 35 as week from dual
)
select a.*
      ,to_date(year || '-01-04', 'yyyy-mm-dd')     - to_number(to_char(to_date(year || '-01-04', 'yyyy-mm-dd'), 'D')) + 1 + (7 * (week-1)) as start_day
      ,to_date(year || '-01-04', 'yyyy-mm-dd') + 7 - to_number(to_char(to_date(year || '-01-04', 'yyyy-mm-dd'), 'D'))     + (7 * (week-1)) as end_day
 from weeks a;

编辑:这些是您需要从周到日范围转换的“转换”表达式。请注意,2017年和39年是可变的...

start date = to_date(2017 || '-01-04', 'yyyy-mm-dd')     - to_number(to_char(to_date(2017 || '-01-04', 'yyyy-mm-dd'), 'D')) + 1 + (7 * (39-1))
end date   = to_date(2017 || '-01-04', 'yyyy-mm-dd') + 7 - to_number(to_char(to_date(2017 || '-01-04', 'yyyy-mm-dd'), 'D'))     + (7 * (39-1))

答案 2 :(得分:0)

对于一年中的第一周和最后一周,此查询需要一些CASE逻辑,但在其他几周内工作正常。此解决方案使用当前的NLS设置。

var express = require('express');
var Layer = require('express/lib/router/layer');

// overwrite the default 'handle_request' with a custom one
Layer.prototype.handle_request_org = Layer.prototype.handle_request;

Layer.prototype.handle_request = function(req, res, next) {
  var fn = this.handle;
  req._lastHandleFunction = fn; // store the last called handler in the request object
  return this.handle_request_org.apply(this, arguments);
}

var app = express();

// register a middleware right at the beginning that will show 
// the last 'handle' used by express for that request
//  and the active handles of node.js
app.use(function(req, res, next) {

  var timeout = setTimeout(() => {
    console.log(req._lastHandleFunction);
    console.dir(process._getActiveHandles())
  }, 1000);

  res.on('finish', () => {
    clearTimeout(timeout)
    console.log('finished')
  });

  next();
});

1)日期'2017-01-01' - 在哪一年,我们寻找几周    或者它可能是截止(sysdate,'年')以占用当年的第一天

2)日期'2017-01-01'+ 38 * 7 - 跳至第38周

3)trunc(...,'day') - 给出一周中第一天的日期

https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions201.htm https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions230.htm

答案 3 :(得分:0)

我使用这个功能:

FUNCTION ISOWeekDate(WEEK INTEGER, YEAR INTEGER) RETURN DATE DETERMINISTIC IS
    res DATE;
BEGIN
    IF WEEK > 53 OR WEEK < 1 THEN
        RAISE VALUE_ERROR;      
    END IF;
    res := NEXT_DAY(TO_DATE( YEAR || '0104', 'YYYYMMDD' ) - 7, 'MONDAY') + ( WEEK - 1 ) * 7;
    IF TO_CHAR(res, 'fmIYYY') = YEAR THEN
        RETURN res;
    ELSE
        RAISE VALUE_ERROR;
    END IF;
END ISOWeekDate;

请注意,根据我的评论,如果您只提供一年没有一年的周数,则不明确。该函数返回给定ISO周的第一天。

答案 4 :(得分:0)

以下是列出2001年至2099年所有ISO周的查询

// the images array holds sources for all the images
function next(){
    var element = document.getElementById("imgs");
    var num = Number(element.src.split("/").slice(-1)[0].split(".")[0]);
    if (num == images.length){
        element.src = "img/1.jpg";
        document.getElementById("count").innerHTML = "1 / 13";
    } else {
        num++;
        element.src = images[num-1];
        document.getElementById("count").innerHTML = num.toString()+" / 13";
    }
}
function prev(){
    var element = document.getElementById("imgs");
    var num = Number(element.src.split("/").slice(-1)[0].split(".")[0]);
    if (num == 1){
        element.src = "img/13.jpg";
        document.getElementById("count").innerHTML = "13 / 13";
    } else {
        num--;
        element.src = images[num].src;
        document.getElementById("count").innerHTML = num.toString()+" / 13";
    }
}
function start(){
    window.timeout = setTimeout("next()", 3000);
    document.getElementById("player").src = "img/pause.png";
    document.getElementById("player").onclick = function(){ stop(); };
    document.getElementById("next_container").onclick = function(){ stop(); next(); start(); };
    document.getElementById("prev_container").onclick = function(){ stop(); prev(); start(); };
}
function stop(){
    clearTimeout(window.timeout);
    document.getElementById("player").src = "img/play.png";
    document.getElementById("player").onclick = function(){ start(); };
    document.getElementById("next_container").onclick = function(){ next(); };
    document.getElementById("prev_container").onclick = function(){ prev(); };
}