Oracle
 sql >> база данни >  >> RDS >> Oracle

Как да генерирате редове за период от време по ключ

в 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 която ще съдържа изчислената дата (т.е. искаме да изчислим начална_дата + 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 (текуща стойност) функция.

така че на ред 1 за Дейвид ще имаме the_date [0] = start_date+0 и впоследствие на ред 2 ще имаме the_date [1] = start_date+1 . целия път до начална_дата+5 (т.е. end_date )

p.s. за свързване от трябва да направите нещо подобно:

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.

но НЕ БИХ препоръчал този подход. неговата производителност ще бъде по-лоша в сравнение с моделния подход (особено ако диапазоните станат големи).



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Грешка при персонализирана заявка за пагиниране при извличане на първите N реда

  2. Как да получа текущата година, използвайки SQL на Oracle?

  3. Неактивна сесия в Oracle от JDBC

  4. SQLDeveloper не показва таблици под връзки, където пише таблици

  5. ORA-00904 невалиден идентификатор на псевдоним за декодиране