Pregunta

Here's what I'm up to: I have some data that represents a goal that students are supposed to reach by a given benchmark (in this case, June 15th). I'm looking at a transactional table and running some rollup queries that attempt to figure out how many students were 'on track' at a given point in time, using the techniques described in 'Filling Gaps in Data' and 'Filling Gaps in an Inventory Table' to calculate running/cumulative totals and densify the data. http://download.oracle.com/docs/cd/B28359_01/server.111/b28313/analysis.htm#i1014934

To express student 'progress to the goal' at each row in the table, I'm trying to figure out fractionally how much of the year is left until June 15th, allowing me to compare the running total to a pro-rated version of the goal.

My data looks like:

Measure    Goal     Year    Week    Date (YYYY-WW)
106141     400000   2011    42      2011-42
128886     400000   2011    43      2011-43
145449     400000   2011    44      2011-44
156921     400000   2011    45      2011-45

I have a workaround, but it's really hacky and awful.

,case 
   when year = 2012 then  24 - week
   when year = 2011 then (52 - week) + 24
   else null
 end as weeks_to_june_15

(June 15th is the 24th week of 2012). Is there a more elegant even marginally correct way to do this? Every time I attempt the calculations using date functions I get illegal number or literal does not match format string errors.

It seemed like someone accomplished something somewhat related to what I was trying to do here: https://forums.oracle.com/forums/thread.jspa?threadID=633028 but I'm not sure if rebuilding that date using IYYY and IW would get me where I want to go.

Using Oracle 11gR2 Express and want to do this in the database, if at all possible.

Thanks!

¿Fue útil?

Solución

This is going to depend a lot on your definition of a week. The IW and IYYY formats use the ISO standard which state that a week always begins on Monday and lasts 7 days. This means that, by the standard, 1/1/2011 was part of the 52nd week of 2010. If this doesn't work for you, then you need to start by defining exactly what you mean by a week.

Because the ISO standard is that well-defined, you can treat the first day of the week as equivalent to the week itself, which will allow you to use date math on it accurately. Below is a function that does just that. You could do it all in SQL as well, but PL/SQL makes this sort of thing a little simpler and easier to read.

CREATE OR REPLACE FUNCTION week_diff(p_year NUMBER, 
                                     p_week NUMBER, 
                                     p_end_date DATE)
   RETURN NUMBER AS
   v_end_date   DATE;
   v_start_date DATE;
   v_weeks      NUMBER;
   v_last_week  DATE;
BEGIN
   v_end_date     := TRUNC(TO_DATE(p_end_date, 'mm/dd/yyyy'), 'IW');
   v_start_date   := TRUNC(TO_DATE('2/1/' || p_year, 'mm/dd/yyyy'), 'IYYY') 
                     + (p_week * 7);

   IF TRUNC(v_end_date, 'IYYY') = TRUNC(v_start_date, 'IYYY') THEN
      v_weeks   := (v_end_date - v_start_date) / 7;
   ELSE
      v_last_week   := TRUNC(TO_DATE('12/31/' || TO_CHAR(v_start_date, 'yyyy'),
                                     'mm/dd/yyyy'), 'IW');
      v_weeks       := (v_last_week - v_start_date) / 7 
                       + TO_NUMBER(TO_DATE(v_end_date, 'IW'));
   END IF;

   RETURN v_weeks;
END week_diff;

Otros consejos

trunc (to_date('15-jun-2012') - sysdate)

will give you the number of calendar days between now and next June 15th.

That should get you started.

If you have a stored date/time data item, this expression:

trunc (stored,'DAY') 

yields midnight on the preceding Sunday (see http://www.techonthenet.com/oracle/functions/trunc_date.php), so for example,

select count(*) events_per_week, 
       trunc(event_time,'DAY') week_starting
  from event
 group by trunc(event_time,'DAY')

will tell you how many events per week you have in the event table. This is a valuable way of summarizing data week by week, because it works over both short and multi-year time periods.

If your business rules require your week to start on Monday, do this instead.

1+trunc(stored-1,'DAY')

If you want a date/time data item from something like '2011-43' then do

to_date('2011-43','YYYY-WW')

or

to_date('2011-43','YYYY-IW')

depending on whether you use ISO week numbers. See http://www.techonthenet.com/oracle/functions/to_date.php.

I much prefer the Sunday-midnight way of identifying a week; it's quite intuitive to read ("Week beginning 13-Nov-2011") and handles end-of-year rollovers in a straightforward way.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top