sql >> Database >  >> RDS >> Oracle

Hoe rijen voor datumbereik te genereren op sleutel

in 10g/11g kunt u hiervoor de modelclausule gebruiken.

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.

dwz uw basisquery:

select rownum id, name, start_date,
       end_date, trunc(end_date)-trunc(start_date) date_range
  from table1

definieert alleen de datums + het bereik (ik gebruikte rijnummer-ID, maar als je een PK hebt, kun je die in plaats daarvan gebruiken.

de partitie splitst onze berekeningen per ID (unieke rij):

6  model partition by(id as key)

de maatregelen:

8        measures(name, start_date, cast(null as date) the_date, date_range)

definieert de attributen die we zullen uitvoeren/berekenen. in dit geval werken we met de naam en de startdatum plus het bereik van de te genereren rijen. daarnaast heb ik een kolom gedefinieerd the_date die de berekende datum bevat (d.w.z. we willen start_date + n berekenen waarbij n van 0 tot het bereik is.

de regels bepalen HOE we onze kolommen gaan vullen:

9        rules (the_date [for f from 0 to date_range[0] increment 1]  = start_date[0] + cv(f),
10               name[any] = name[0]);

dus met 

the_date [for f from 0 to date_range[0] increment 1]

we zeggen dat we het aantal rijen zullen genereren dat date_range bevat+1 (dwz 6 datums in totaal). de waarde van f kan worden verwezen via de cv (huidige waarde) functie.

dus op rij 1 voor david hebben we the_date [0] = start_date+0 en vervolgens zouden we in rij 2 the_date [1] = start_date+1 . hebben . helemaal tot aan start_date+5 (d.w.z. de end_date )

p.s. voor verbinding maken door zou je zoiets als dit moeten doen:

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;

d.w.z. isoleer de verbinding door met een subquery en filter vervolgens de rijen uit waar individual_day> end_date.

maar ik zou deze aanpak NIET aanbevelen. de prestaties zullen slechter zijn in vergelijking met de modelbenadering (vooral als het bereik groot wordt).



  1. 'De opgegeven invoer vertegenwoordigt geen geldige geografie-instantie' uitzondering bij gebruik van SqlGeographyBuilder

  2. Bestellen door binnen groep door in Leer 2

  3. Hoe LocalTime op te slaan in de slaapstand

  4. Queryresultaten retourneren als een door komma's gescheiden lijst in SQL Server - STRING_AGG()