如何在两个给定日期之间将行拆分为多行?

时间:2015-11-10 09:04:28

标签: sql oracle date-arithmetic

如何使用

拆分行
Start Date : 02-OCT-2015
End Date   : 31-DEC-2015

进入Oracle下面的行?

02-OCT-2015 31-OCT-2015
01-NOV-2015 30-NOV-2015
01-DEC-2015 31-DEC-2015

3 个答案:

答案 0 :(得分:2)

SELECT SUBSTR(t.column_one, 1, INSTR(t.column_one, ' ')-1) AS col_one,
SUBSTR(t.column_one, INSTR(t.column_one, ' ')+1) AS col_two
FROM YOUR_TABLE t

<强>替代地 您可以使用正则表达式或子字符串函数。它在非常大的数据集上不会超快,但它可以完成工作。 as -

SELECT REGEXP_SUBSTR(t.column_one, '[^-]+', 1, 1) col_one,
REGEXP_SUBSTR(t.column_one, '[^-]+', 1, 2) col_two,
REGEXP_SUBSTR(t.column_one, '[^-]+', 1, 3) col_three,
FROM YOUR_TABLE t;

希望这会有所帮助。

答案 1 :(得分:2)

您可以使用以下方式完成所需的 DATE算术

  • ADD_MONTHS
  • LAST_DAY
  • TRUNC
  • CONNECT BY ,即典型的行生成器
  • CASE 表达

我们假设您有两个日期为开始结束日期,以下查询将日期拆分为多行基于 MONTHS

SQL> WITH sample_data AS
  2    (SELECT DATE '2015-10-02' Start_Date, DATE '2015-12-25' End_Date FROM DUAL)
  3  -- end of sample_date to mock an actual table
  4  SELECT CASE
  5         WHEN start_date >= TRUNC(add_months(start_date,COLUMN_VALUE - 1),'MM')
  6         THEN
  7            TO_CHAR(start_date, 'YYYY-MM-DD')
  8         ELSE
  9            TO_CHAR(TRUNC(add_months(start_date,COLUMN_VALUE - 1),'MM'),'YYYY-MM-DD')
 10         END new_start_date,
 11         CASE
 12         WHEN end_date <= last_day(TRUNC(add_months(start_date,COLUMN_VALUE - 1),'MM'))
 13         THEN
 14            TO_CHAR(end_date, 'YYYY-MM-DD')
 15         ELSE
 16            TO_CHAR(last_day(TRUNC(add_months(start_date,COLUMN_VALUE - 1),'MM')),
 17                    'YYYY-MM-DD')
 18         END new_end_date
 19  FROM sample_data,
 20    TABLE(
 21          CAST(
 22               MULTISET
 23                       (SELECT LEVEL
 24                        FROM dual
 25               CONNECT BY add_months(TRUNC(start_date,'MM'),LEVEL - 1) <= end_date
 26                       ) AS sys.OdciNumberList
 27              )
 28         )
 29  ORDER BY column_value;

NEW_START_DATE NEW_END_DATE
-------------- ------------
2015-10-02     2015-10-31
2015-11-01     2015-11-30
2015-12-01     2015-12-25

查询的工作原理:

如果您应该使用 CONNECT BY子句了解行生成的工作原理,那么其余的就是简单的 DATE 算术。

  • TRUNC(date, 'MM')给出了该月的第一天,在您的情况下,它将成为开始日期。

  • ADD_MONTHS(date, value)会在中指定的日期添加多个月。

  • LAST_DAY给出了该月的最后一天,在您的情况下成为结束日期。

答案 2 :(得分:2)

所以你有你想要比较的范围:第一个范围是你感兴趣的时期(02-OCT-2015到31-DEC-2015),其他范围是几个月(01-OCT-2015到31-OCT) -2015)...是的,我知道你只想要02-OCT-2015,因为你的数据,但让我们做一件事......我们会到达那里!

你感兴趣的时期是从今天起的未来,所以你的答案需要展望未来。

这就是我的所作所为:

第1步: 列出月份,定义每个月的开始日期和结束日期: 这可以是表格或视图。我发表意见。

create view mymonths as 
select 
  add_months(trunc(sysdate,'MONTH'), - rownum + 2) month_start,
  add_months(trunc(sysdate,'MONTH'), - rownum + 3) -1 month_end,
from all_objects -- (or any table or view with enough rows)
where rownum < 13
-- today is 10-NOV-2015. 
-- First row will month_start = 01-NOV-2015, minus 1 (the rownum) month = 01-OCT-2015 + 2 = 01-DEC-2015 and month_end = 31-DEC-2015 (find the next month_start, minus a day) 
-- Next row = 01-NOV-2015 and 30-NOV-2015
-- Next row = 01-OCT-2015 and 31-OCT-2015...for 12 rows down
-- adjust the +3 and < 13 as necessary for the scope of your data

现在我们需要准备好我们的数据来加入我们的month_starts和month_ends:

如果列数据如下所示: 开课日期:02-OCT-2015结束日期:2015年12月31日 然后按照回复中的建议,我们可以使用substr来获取数据部分。

只是为了证明这个想法,让我们做一个这样的观点:

create view mydata as
select 
   to_date(substr(column,13,11),'dd-MON-yyyy') period_start,
   to_date(substr(column,35,11),'dd-MON-yyyy') period_end
from MYTABLE

现在我们可以像这样“加入”:

Select
   mydata.period_start, mydata.period_end,
   mymonths.month_start, mymonths.month_end
From
   mytable, mymonths
Where
   -- this is tricky, but work it out: it's right...
   mydata.period_start <= mymonths.month_end 
   and
   mydata.period_end => my_months.month_start

- 看看结果,看看我们差不多了。但是你想要02-OCT-2015到2015年10月31日,或者让我们说句号开始或月开始 - 以最新和月末为准,我们会说句号为月末或月末,这是最早的:

Select
   case
     when mydata.period_start > mymonths.month_start
       then mydata.period_start 
     else mymonths.month_start
   end COL1,
   case
     when mydata.period_end < mymonths.month_end
       then mydata.period_end
     else mymonths.month_end
   end COL2
From
   mytable, mymonths
Where
   -- this is tricky, but work it out: it's right...
   mydata.period_start <= mymonths.month_end 
   and
   mydata.period_end => my_months.month_start