如何在两个给定日期之间将一行拆分为多行?
How to split a row into multiple rows between two given dates?
如何用
拆分一行
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
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
或者
您可以使用正则表达式或子字符串函数。它在非常大的数据集上不会很快,但它会完成工作。作为 -
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;
希望这对您有所帮助。
您想要的 DATE 算法 可以使用以下方法完成:
- ADD_MONTHS
- LAST_DAY
- TRUNC
- CONNECT BY 即典型的行生成器
- CASE表达式
假设您有两个日期 start 和 end 日期,以下查询将 将日期拆分为基于 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
给出该月的最后一天,在您的情况下成为结束日期。
所以你有你想要比较的范围:第一个范围是你感兴趣的时期(2015 年 10 月 2 日到 2015 年 12 月 31 日)其他范围是月份(2015 年 1 月 1 日到 31 -OCT-2015)...是的,我知道您只想要 02-OCT-2015 因为您的数据,但让我们一次做一件事...我们会到达那里!
你感兴趣的时期从今天开始进入未来,所以你的答案需要展望未来。
我就是这样做的:
第 1 步:
列出月份,定义每个月的开始日期和结束日期:
这可以是 table 或视图。我发表看法。
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
现在我们需要准备好数据以 'join' 与我们的 month_starts 和 month_ends:
如果列数据如下所示:
开始日期:2015 年 10 月 2 日结束日期: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
现在我们可以 'join' 像这样:
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
-- 查看结果,我们就快完成了。但是你想要 2015 年 10 月 2 日到 2015 年 10 月 31 日,或者说 period_start 或月开始 - 以最晚者为准,在月末,我们会说 period_end 或月末, 谁是最早的:
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
如何用
拆分一行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
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
或者 您可以使用正则表达式或子字符串函数。它在非常大的数据集上不会很快,但它会完成工作。作为 -
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;
希望这对您有所帮助。
您想要的 DATE 算法 可以使用以下方法完成:
- ADD_MONTHS
- LAST_DAY
- TRUNC
- CONNECT BY 即典型的行生成器
- CASE表达式
假设您有两个日期 start 和 end 日期,以下查询将 将日期拆分为基于 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
给出该月的最后一天,在您的情况下成为结束日期。
所以你有你想要比较的范围:第一个范围是你感兴趣的时期(2015 年 10 月 2 日到 2015 年 12 月 31 日)其他范围是月份(2015 年 1 月 1 日到 31 -OCT-2015)...是的,我知道您只想要 02-OCT-2015 因为您的数据,但让我们一次做一件事...我们会到达那里!
你感兴趣的时期从今天开始进入未来,所以你的答案需要展望未来。
我就是这样做的:
第 1 步: 列出月份,定义每个月的开始日期和结束日期: 这可以是 table 或视图。我发表看法。
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
现在我们需要准备好数据以 'join' 与我们的 month_starts 和 month_ends:
如果列数据如下所示: 开始日期:2015 年 10 月 2 日结束日期: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
现在我们可以 'join' 像这样:
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
-- 查看结果,我们就快完成了。但是你想要 2015 年 10 月 2 日到 2015 年 10 月 31 日,或者说 period_start 或月开始 - 以最晚者为准,在月末,我们会说 period_end 或月末, 谁是最早的:
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