Working from an oracle 10g environment.
Suppose you were given: *NOTE (Duration is in Weeks)
CLASSNAME INSTURCTOR DAYS STARTDATE *DURATION TIMESTART TIMEEND
------------------------- ----------------------- ------------- --------- -------- --------
Power Dance Robert Backman MWF 03-MAR-11 2 0930 1100
Power Dance Lynn Parker MWF 03-MAY-11 2 0930 1100
Power Dance Lynn Parker MTTh 18-MAY-11 2 1230 0100
Club Stretch Kevin Lopez MT 24-OCT-11 3 1930 2015
Club Stretch Kevin Lopez F 17-JUN-11 3 1130 1300
Hatha Yoga Susan Wanzer MW 25-MAY-11 3 1900 2000
A user wants to be able to query the Classname, Instructor, Timestart, and TimeEnd for a class given a specific date.
I understand how to find the EndDate using (Duration * 7) + StartDate. The trouble I am having is finding out which classes are running on a day of the week. As in say the user enters in 24-JUN-11, the only class that should show up should be Club Stretch.
It might be just a matter of rephrasing your question: you want to know which classes are starting at of before the specified date and are ending at or after this specified date.
You already have the starting date and you know how to calculate the ending date.
This will be your solution:
SELECT [columns]
FROM [table]
WHERE #specifiedDate BETWEEN [startDate] AND [calculatedEndDate]
AND [days] LIKE #specifiedWeekday
#specifiedWeekday should, when looking for a Monday, have a value like this (in MS SQL): '%M%'
NOTE: Just now read your working in Oracle. This is a SQL Server answer. I hope the idea behind it will help you along.
Looks to me that you need to first determine the day of the week store that as a variable that you would feed to the second to the second query. Query sample for first part below:
select to_char(to_date('31-May-2011','dd-Mon-yyyy'),'DAY') from dual
SQL> /
TO_CHAR(T
---------
TUESDAY
or
select to_char(to_date('31-May-2011','dd-Mon-yyyy'),'DY') from dual
TO_
---
TUE
then you could feed that into your other query with your now known day of the week. If you need to decode it to the formats you mention then the following code will convert the day of the week to the abbreviations you are showing:
select decode(to_char(to_date('26-May-2011','dd-Mon-yyyy'),'DY'), 'MON','M',
'TUE','T',
'WED','W',
'THU','Th',
'FRI','F',
'SAT','Sa','Su')
from dual
will return the Th you are using :)
Related
Let's say I have an employees list and I log inside "log" table the beginning and the end of the employee working day. Example:
ID
NAME
BEGINTIME
ENDTIME
1
Mary
05/04/2021 07:10
05/04/2021 10:10
2
John
05/04/2021 09:10
05/04/2021 14:10
And I want to search: how many employees where working at the same time (interval) and the number of them (if more than 1) and sort them from max to min.
Example: Mary and John were working at the same time May 4th from 09:10 to 10:10, before 09:10 Mary was alone, then John came at 10:10 and they were two employee working at the office (the max in that example) then Mary left the office at 10:10 and John was alone.
The point is due to COVID19, I want to know for on a specific date (May 4th in that example) when we had the more employees working in the office at the same time, to split them to lower that max.
Exepected result (the first row is to define the aim) :
MAXEMPLOYEES
FROMBEGINTIME
TOENDTIME
LISTAGG
120
dd/MM/YYYY HH:mm
dd/MM/YYYY HH:mm
...
2
05/04/2021 09:10
05/04/2021 10:10
Mary, John
I really don't know where to start, maybe I thought, find all the log for the May 4th (let's say 1000 row) and loop, first row then loop again to the other logs and if MYSELECTEDROWBEGINTIME >= NthBEGINTIME AND MYSELECTEDROWENDTIME <= NthENDTIME and loop to my list and then go the 2nd row etc.
For 12-12:30 interval, you can start working on this query:
select count(*) employees_count
from log
where begintime<to_date('05/04/2021 12:30','MM/DD/YYYY HH24:MI')
and endtime>to_date('05/04/2021 12:00','MM/DD/YYYY HH24:MI');
I'm assuming that the begintime and endtime are of date type. In general, your condition should be begintime<interval_endtime and endtime>interval_begintime.
For your example output in your original post, you may need a table for the time interval to be joined to log, which would look like this:
int_id
int_from
int_to
1
09:10
10:10
2
12:00
12:30
and your query for May 4, 2021 can be something like this:
select count(*) maxemployee,
int_from frombegintime,
int_to toendtime
from (
select log.id, log.begintime, log.endtime,
tint.int_from, tint.int_to
from log
join time_interval tint
on log.begintime<to_date('05/04/2021 '||tint.int_to,'MM/DD/YYYY HH24:MI')
and log.endtime>to_date('05/04/2021 '||tint.int_from,'MM/DD/YYYY HH24:MI')
) t
group by int_from, int_to
I have an Oracle table filled with call information. I have the call datetime field (calldate). Each record represents one call. How do I find the average number of calls per hour by year?
Sample data:
Calldate Account Name
1/20/2016 10:16:09 AM 12345 Blee
1/20/2016 11:17:02 AM 45678 Foo
Something like:
1:00 AM 23
2:00 AM 22
3:00 AM 19
Thank you!
Something like:
select to_char(calldate, 'YYYY-HH24') as yyyyhh,
count(*) / count(distinct trunc(calldate)) as avg_per_hour
from t
group by to_char(calldate, 'YYYY-HH24')
order by yyyyhh;
Note: This treats days with no calls as NULL, rather than zero.
I currently have a report that uses DATEPART to return the week a 'car' was returned. However, the business I work for fiscal year starts first Sunday of the year (this instance commencing 03/01/2016 would be week 1). However, using SQL 'DATEPART wk' would return this date is week 2:
Current outcome using DATEPART (wk, year etc):
CarTitle ReturnDate Year Week
Car 1 30/12/2015 2015 53
Car 2 02/01/2016 2016 1
Car 3 03/01/2016 2016 2
Car 4 05/01/2016 2016 2
Car 5 10/01/2016 2016 3
Car 6 17/01/2016 2016 4
Example of expected outcome:
CarTitle ReturnDate Year Week
Car 1 30/12/2015 2015 53
Car 2 02/01/2016 2015 53
Car 3 03/01/2016 2016 1
Car 4 05/01/2016 2016 1
Car 5 10/01/2016 2016 2
Car 6 17/01/2016 2016 3
I can calculate this with the following SQL:
SELECT
CarTitle,
DATEPART(ISO_WEEK, DATEADD(day, 1, ReturnDate))
FROM
dbo.My_Table
However, this depends on your localization settings (which are probably different from mine given how you express dates) and if you use this code throughout your system and then the business decides to change it's method for calculating weeks then you could end up with a big refactorization headache.
I prefer to use a Calendar table for this sort of thing:
CREATE TABLE dbo.Calendar (
calendar_date DATE NOT NULL,
week_number SMALLINT NOT NULL,
is_holiday BIT NOT NULL,
name VARCHAR(30) NOT NULL, -- i.e. 'January 6th, 2016'
CONSTRAINT PK_Calendar PRIMARY KEY CLUSTERED (calendar_date)
)
You can expand the table as needed, for example if accounting uses a different definition for week of the year than another department then that's easy to accommodate by adding another column. This then makes your query a simple join to get the week number:
SELECT
MT.CarTitle,
MT.ReturnDate,
CAL.week_number
FROM
My_Table MT
INNER JOIN dbo.Calendar CAL ON CAL.calendar_date = MT.ReturnDate
You'll need to populate the table, but that should be a one time effort (populate it for 50 years in advance and it's still a pretty small table) and you can use code similar to my first statement to generate the values - don't enter each date by hand ;) After that you just need to maintain the table if the business logic changes (which is easier than changing all of your queries that deal with dates) or if you get a new requirement that needs a new column.
I'm getting a peculiar problem with an Oracle view I've modified. The idea is I have a base table that stores all election candidates and also has an election date column, telling us what election this candidate was part of, like so.
NAME | ELECTION_DATE
---------------------------
John Smith | 01-APR-2011
Alan Cooper| 02-MAY-2013
The ELECTION_DATE column is stored as a date. We constructed 2 views for 2011 and 2013, using the following statment for 2011.
where election_date >= to_date(2011,'yyyy') and election_date < to_date(2012,'yyyy')
Which we thought would pick up just the John Smith record above, but it didn't. The peculiar thing was that when we did this for the 2013 view.
where election_date >= to_date(2013,'YYYY') and election_date < to_date(2014,'YYYY')
It DID get just the Alan Cooper record. Even more peculiar is that if we did this for the 2011 view.
where election_date >= to_date(2010,'yyyy') and election_date < to_date(2011,'yyyy')
We got just the John Smith record and not the Alan Cooper record, which is what we wanted but not what we expected.
We then changed them both to between statements and they behaved exactly the same i.e. between 2010 and 2011 got the John Smith record, between 2011 and 2012 got nothing and between 2013 and 2014 got the Alan Cooper record.
Whilst I was writing this my colleague managed to fix it by using this more explicit statement.
where election_date between '01-JAN-2011' AND '01-JAN-2012'
But I still want to know why the above statements still worked so strangely? Something I am missing about using to_date functions for just years maybe?
Did you look at what your to_date() functions actually produced?
select to_date(2011, 'yyyy'), to_date(2012, 'yyyy'), to_date(2013, 'yyyy')
from dual;
TO_DATE(2011,'Y TO_DATE(2012,'Y TO_DATE(2013,'Y
--------------- --------------- ---------------
01-MAY-11 01-MAY-12 01-MAY-13
Based on those dates the results you got are correct.
If you don't specify the month and day then they default to the first day of the current month, although the time defaults to midnight. From the documentation for date time literals, which is the only official reference I can find for this behaviour:
If you specify a date value without a time component, then the default
time is midnight (00:00:00 or 12:00:00 for 24-hour and 12-hour clock
time, respectively). If you specify a date value without a date, then
the default date is the first day of the current month.
If you're going to use
where election_date between '01-JAN-2011' AND '01-JAN-2012'
... then you should still use to_date() as you're relying on a default date format mask that might change in the future, and is session dependent. between is also inclusive, so using that your 2011 view would include an election held on 01-Jan-2012, which probably isn't what you want, so using >= and < is maybe safe. Alternatively use date literals:
where election_date >= date '2011-01-01' and election_date < date '2012-01-01'
Try extracting the year as a VARCHAR2 and doing the comparison
select * from table where to_char(ELECTION_DATE, 'yyyy') = `2011`
or to_char(ELECTION_DATE, 'yyyy') = '2012'
I am using Oracle's to_char() function to convert a date to a week number (1-53):
select pat_id,
pat_enc_csn_id,
contact_date,
to_char(contact_date,'ww') week,
...
the 'ww' switch gives me these values for dates in January of this year:
Date Week
1-Jan-10 1
2-Jan-10 1
3-Jan-10 1
4-Jan-10 1
5-Jan-10 1
6-Jan-10 1
7-Jan-10 1
8-Jan-10 2
9-Jan-10 2
10-Jan-10 2
11-Jan-10 2
12-Jan-10 2
a quick look at the calendar indicates that these values should be:
Date Week
1-Jan-10 1
2-Jan-10 1
3-Jan-10 2
4-Jan-10 2
5-Jan-10 2
6-Jan-10 2
7-Jan-10 2
8-Jan-10 2
9-Jan-10 2
10-Jan-10 3
11-Jan-10 3
12-Jan-10 3
if I use the 'iw' switch instead of 'ww', the outcome is less desirable:
Date Week
1-Jan-10 53
2-Jan-10 53
3-Jan-10 53
4-Jan-10 1
5-Jan-10 1
6-Jan-10 1
7-Jan-10 1
8-Jan-10 1
9-Jan-10 1
10-Jan-10 1
11-Jan-10 2
12-Jan-10 2
Is there another Oracle function that will calculate weeks as I would expect or do I need to write my own?
EDIT
I'm trying to match the logic used by Crystal Reports. Each full week starts on a Sunday; the first week of the year starts on whichever day is represented by January 1st (e.g. in 2010, January 1st is a Friday).
When using IW, Oracle follows the ISO 8601 standard regarding week numbers (see http://en.wikipedia.org/wiki/ISO_8601). That is the same standard than the one we generally use in Europe here.
Your problem is also mentioned on the Oracle forum: http://forums.oracle.com/forums/thread.jspa?threadID=947291 and http://forums.oracle.com/forums/message.jspa?messageID=3318715#3318715. Maybe you can find a solution there.
I know this is old, but still a common question.
This should give you the correct results in the smallest amount of effort:
select pat_id,
pat_enc_csn_id,
contact_date,
to_char(contact_date + 1,'IW') week,
...
Since it looks like you are using your own special definition of the week number you'll need to write your own function.
It might be helpful that NLS_TERRITORY affects the day with which a week starts as used by the D Format Model
see also:
http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements004.htm#SQLRF00210
and
http://www.adp-gmbh.ch/ora/sql/to_char.html
Based on this question, How do I calculate the week number given a date?, I wrote the following Oracle logic:
CASE
--if [date field]'s day-of-week (e.g. Monday) is earlier than 1/1/YYYY's day-of-week
WHEN to_char(to_date('01/01/' || to_char([date field],'YYYY'),'mm/dd/yyyy'), 'D') - to_char([date field], 'D') > 1 THEN
--adjust the week
trunc(to_char([date field], 'DDD') / 7) + 1 + 1 --'+ 1 + 1' used for clarity
ELSE trunc(to_char([date field], 'DDD') / 7) + 1
END calendar_week