我在处理以下查询时遇到问题:
SELECT
B.EMPLOYEE_NAME,
A.START_DATE+(LEVEL-1) AS INDIVIDUAL_DAY,
TO_CHAR(A.START_DATE,'MM/DD/YYYY') START_DATE,
TO_CHAR(A.END_DATE,'MM/DD/YYYY') END_DATE
FROM table1 A
INNER JOIN table2 B ON A.EMPLOYEE_NAME = B.EMPLOYEE_NAME
CONNECT BY LEVEL-1 <= (A.END_DATE-A.START_DATE);
如果表 A 中只有一条记录,那么我得到的正是我要查找的内容。但是,如果有多个记录,那么我会得到过多的结果。
我在找什么:
我有一个表,其中的行具有 EMPLOYEE_NAME
、START_DATE
和 END_DATE
字段。我想把这一行信息变成多行。示例:
当前 -
NAME START END
DAVID SMITH 1-1-2001 1-6-2011
JOHN SMITH 2-7-2012 2-9-2012
期望-
NAME DATE
DAVID SMITH 1-1-2001
DAVID SMITH 1-2-2001
DAVID SMITH 1-3-2001
DAVID SMITH 1-4-2001
DAVID SMITH 1-5-2001
DAVID SMITH 1-6-2001
JOHN SMITH 2-7-2012
JOHN SMITH 2-8-2012
JOHN SMITH 2-9-2012
关于如何实现此目标的任何想法? 注意:我使用的是 Oracle 10 和 11。
最佳答案
在 10g/11g 中,您可以为此使用模型子句。
SQL> with emps as (select rownum id, name, start_date,
2 end_date, trunc(end_date)-trunc(start_date) date_range
3 from table1)
4 select name, the_date
5 from emps
6 model partition by(id as key)
7 dimension by(0 as f)
8 measures(name, start_date, cast(null as date) the_date, date_range)
9 rules (the_date [for f from 0 to date_range[0] increment 1] = start_date[0] + cv(f),
10 name[any] = name[0]);
NAME THE_DATE
----------- ----------
DAVID SMITH 01-01-2001
DAVID SMITH 01-02-2001
DAVID SMITH 01-03-2001
DAVID SMITH 01-04-2001
DAVID SMITH 01-05-2001
DAVID SMITH 01-06-2001
JOHN SMITH 02-07-2012
JOHN SMITH 02-08-2012
JOHN SMITH 02-09-2012
9 rows selected.
即您的基本查询:
select rownum id, name, start_date,
end_date, trunc(end_date)-trunc(start_date) date_range
from table1
仅定义日期 + 范围(我使用了 rownum id,但如果您有 PK,则可以改用它。
分区根据 ID(唯一行)拆分我们的计算:
6 model partition by(id as key)
措施:
8 measures(name, start_date, cast(null as date) the_date, date_range)
定义我们将输出/计算的属性。在这种情况下,我们使用名称和开始日期加上要生成的行范围。此外,我定义了一个 the_date
列,它将保存计算出的日期(即我们要计算 start_date + n,其中 n 是从 0 到范围。
规则定义了我们将如何填充我们的列:
9 rules (the_date [for f from 0 to date_range[0] increment 1] = start_date[0] + cv(f),
10 name[any] = name[0]);
所以
the_date [for f from 0 to date_range[0] increment 1]
我们是说我们将生成 date_range 包含的行数+1(即总共 6 个日期)。 f
的值可以通过cv
(current value)函数来引用。
所以对于大卫的第 1 行,我们有 the_date [0] = start_date+0
然后在第 2 行,我们有 the_date [1] = start_date+1
。一直到 start_date+5(即 end_date
)
附注 对于 connect by 你需要做这样的事情:
select
A.EMPLOYEE_NAME,
A.START_DATE+(b.r-1) AS INDIVIDUAL_DAY,
TO_CHAR(A.START_DATE,'MM/DD/YYYY') START_DATE,
TO_CHAR(A.END_DATE,'MM/DD/YYYY') END_DATE
FROM table1 A
cross join (select rownum r
from (select max(end_date-start_date) d from table1)
connect by level-1 <= d) b
where A.START_DATE+(b.r-1) <= A.END_DATE
order by 1, 2;
即将连接隔离到子查询,然后过滤掉 individual_day > end_date 的行。
但我不会推荐这种方法。与模型方法相比,它的性能会更差(尤其是当范围变大时)。
关于sql - 如何按键生成日期范围的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14469652/