MySql string search as Date using LIKE - mysql

I am managing a system designed 10 years ago for booking lessons.
The data structure saves the startTime as a string in the format YYYYmmDDHHMM and same format as lesson endTime.
How can I run a query which can get me all the lessons booked at HHMM (0930 or 1630) in future only?
The lesson may be an hour long and booked from 09:00 to 10:00, so If I put the search time as 09:30 this lesson should be returned as well.
Thank you

You could use a combination of STR_TO_DATE and RIGHT:
SELECT ...
WHERE STR_TO_DATE(startTime, '%Y%m%d%H%i') > CURDATE() AND
(RIGHT(startTime, 4) = '0930' OR RIGHT(startTime, 4) = '1630')
Update
To look for lessons which may overlap the desired time (e.g. a lesson that goes from 9am to 10am) is a little more complicated. Basically we also need to get the time part of the value and check for it surrounding 9:30 or 16:30 e.g.
SELECT ...
WHERE STR_TO_DATE(startTime, '%Y%m%d%H%i') > CURDATE() AND
('09:30' BETWEEN TIME(STR_TO_DATE(startTime, '%Y%m%d%H%i')) AND TIME(STR_TO_DATE(endTime, '%Y%m%d%H%i')) OR
'16:30' BETWEEN TIME(STR_TO_DATE(startTime, '%Y%m%d%H%i')) AND TIME(STR_TO_DATE(endTime, '%Y%m%d%H%i')))

Related

What's the difference between the two SQL statements?

This is a question from leetcode, using the second query I got the question wrong but could not identify why
SELECT
user_id,
max(time_stamp) as "last_stamp"
from
logins
where
year(time_stamp) = '2020'
group by
user_id
and
select
user_id,
max(time_stamp) as "last_stamp"
from
logins
where
time_stamp between '2020-01-01' and '2020-12-31'
group by
user_id
The first query uses a function on every row to extract the year (an integer) and compares that to a string. (It would be preferable to use an integer instead.) Whilst this may be sub-optimal, this query would accurately locate all rows that fall into the year 2020.
The second query could fail to locate all rows that fall into 2020. Here it is important to remember that days have a 24 hour duration, and that each day starts at midnight and concludes at midnight 24 hours later. That is; a day does have a start point (midnight) and an end-point (midnight+24 hours).
However a single date used in SQL code cannot be both the start-point and the end-point of the same day, so every date in SQL represents only the start-point. Also note here, that between does NOT magically change the second given date into "the end of that day" - it simply cannot (and does not) do that.
So, when you use time_stamp between '2020-01-01' and '2020-12-31' you need to think of it as meaning "from the start of 2020-01-01 up to and including the start of 2020-12-31". Hence, this excludes the 24 hours duration of 2020-12-31.
The safest way to deal with this is to NOT use between at all, instead write just a few characters more code which will be accurate regardless of the time precision used by any date/datetime/timestamp column:
where
time_stamp >= '2020-01-01' and time_stamp <'2021-01-01'
with the second date being "the start-point of the next day"
See answer to SQL "between" not inclusive

Get data from past 7 days DB2

I have no experience working with DB2 before and I'm kind of stuck in something. I'm working on a project in SSIS reading from DB2 where I write into a flat file. I need to run the process weekly and get data from past 7 days.
My query works this way:
Select * From Table
Where ServiceDate >= 2200624 - 7
The above query brings data from the past 7 days, but this query don't work for me since I need to execute this process weekly. I need something like this:
Select * From Table
Where ServiceDate >= DATE(CURRENT_DATE - 7 DAY)
The second query throws an error, is there any other way to achieve this? I'm using ODBC source and I was thinking to use a dynamic query in SSIS but I'm not sure how this works in ODBC source, any suggestions or help will be appreciated.
EDIT:
This tables were created a long time ago, so I don't have any information about the data type of these tables.
The actual date 2200624 correspond to 20200624. This is the way that my date shows in the table.
Thanks in advance
For ServiceDate as YYYYMMDD INT:
Select * From Table
Where ServiceDate >= INT(TO_CHAR(CURRENT_DATE - 7 DAY, 'YYYYMMDD'));
If ServiceDate is CHAR(7) or equivalent, and if value 2200624 corresponds to YYYYMMDD date 20200624 as per your edited question, then the following examples might help.
It assumes ServiceDate values beginning with first character 1 are in the 20th century (19xx years), and dates with first character 2 are in the 21st century.
SELECT ... FROM ... WHERE ( TO_DATE(CASE SUBSTR(ServiceDate,1,1) WHEN '1' THEN '19'||SUBSTR(ServiceDate,2,6) WHEN '2' THEN '20'||SUBSTR(ServiceDate,2,6) END,'YYYYMMDD')) >= CURRENT DATE - 7 DAYS
This will perform badly, so don't use that!
An alternative that will perform better is to convert CURRENT DATE - 7 DAYS into a number that matches your storage-format like this:
...WHERE ServiceDate >= '2'||substr(TO_CHAR(CURRENT_DATE - 7 DAY, 'YYYYMMDD'),2,6)
and if ServiceDate is INTEGER column datatype then:
...WHERE ServiceDate >= int('2'||substr(TO_CHAR(CURRENT_DATE - 7 DAY, 'YYYYMMDD'),2,6))
Always state your Db2-server platform (Z/OS, i-series, Linux/Unix/Windows) when asking for help with Db2, because the answer may be different depending on the platform + version of your Db2-server.

Optimized SQL for timetable

I want to create a SQL table in my database that can hold a school timetable but every way i tried to proceed with it it was no optimal and over the course of 1-2 changes to the timetable the database table got a bit too big.
It goes a bit like this:
Mo Tu Wed Thu Fri
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
This is the basic layout of the timetable and in the table the first 2 columns are timetableid and classid. My first approach was to have columns for each day with the classes in one column but that was a bit buggy, my next approach was to get the columns like this mo_7, mo_8, mo_9 etc. until i reach fri_16 but that took up too much space.
So my question is, what is the most optimal way to save a timetable in a database, in what table layout.
Thank you in advance.
Your problem isn't your database, it's because you're trying to use it like a spreadsheet.
You need to backtrack a little - store a table of classes, along with the various attributes. If each class has only one session, then add 'time' as an attribute. If there's multiple sessions, your probably then need to separate out the schedule into a seperate table.
E.g.:
Table 'classes':
ClassID.
description
teacher
other stuff.
Table 'sessions':
session ID
ClassID
start_time
end_time
day
location
And then you'd use a select to query e.g.
SELECT classID, start_time, day, location
FROM sessions
WHERE day like "Monday"
ORDER BY start_time
Which'd give you your list for Monday. To extend it, you might add a join with the 'classes' table.
SELECT classes.description, classes.teacher, sessions.start_time, sessions.day, sessions.location
FROM sessions, classes
JOIN ON classes.ClassID = sessions.ClassID
WHERE day LIKE 'Monday'
ORDER BY sessions.start_time
Something like that anyway (apologies if the syntax is a bit off, I'll check/amend if I can).
But the point is - let the database store the actual data and use the queries to transform it into a layout that you like. That way you don't need to rewrite your database each time you want to change something minor.

Bringing in Schedules for Access calculations

I really don't know how to ask this question or title it but here I go. I work in a school system and I have created a database for some psychologists to use to track their referrals. By state rules,they have 60 days from the date of their first meeting to finish the process. Weekends still count but HOLIDAYS DO NOT. I do not really know how to use the calender we have so that we have an accurate Calculation. For instance, with Holidays accounted for, if a kid was started today, he would need to have everything finished on 1/18/2013 That is 60 days from now based on our schedule. Does anyone have any idea where I should start?
Edit
Ok, so I now have a Calender table. Here is my issue. I have my column that I used to indicate which days are used in calculating my 60 days. Weekends can be used in that calculation. HOWEVER, they cannot be used in the result. If the 60th day lies on a Sunday or Saturday, then the date would need to go to the Friday before. I guess my first issue is really, how do I limit my calculation to the dates in my calender table?
This can be easy with a calendar table.
PARAMETERS start_date DateTime;
SELECT TOP 1 sub.the_date
FROM
(
SELECT TOP 60 the_date
FROM tblCalendar
WHERE
the_date>=[start_date]
AND work_day=True
ORDER BY the_date
) AS sub
ORDER BY sub.the_date DESC;
That query is based on the assumption you have set work_day to True for the dates you want evaluated. IOW, work_day will be False only for your organization's holidays.
For sample code to create and load your calendar table, see the CreateTable_calendar() and LoadCalendar() procedures at Using Start Date and End date in Access query. To initially assign all dates including weekend days as work days, make this change in LoadCalendar().
'rs!work_day = Not (Weekday(dte) = vbSunday Or _
' Weekday(dte) = vbSaturday)
rs!work_day = True
Finally, manually edit the table to change work_day to False for your holidays.
You can check the weekday to ensure you have not chosen a weekend:
SELECT TOP 1 CalDate, WDay
FROM (SELECT Top 60 c.CalDate,Weekday([Caldate]) AS WDay
FROM Calendar c
WHERE c.Holiday=False) a
WHERE WDay Not In (1,7)
ORDER BY CalDate DESC

Time difference between dates, including business hour and excluding holidays

How can I calculate the time difference between two date, considering:
Only Monday to Friday
Time between 9am to 5:30pm;
Exclude Holidays.
Example:
d1 = 2012-10-05 17:00:00
d2 = 2012-14-09 12:00:00
Calculation Steps:
2012-10-05 = 00:30:00
2012-10-06 = 00:00:00
2012-10-07 = 00:00:00
2012-10-08 = 07:30:00
2012-10-09 = 04:00:00
ddiff(d2,d1) = 12:00:00
I know how to do it using only mon-fri, as described here. And I am talking about MySQL.
I've come up with a solution that's relatively straightforward for calculating the time difference for the full interim dates. However it's a bit messy to use mysql for calculating the time difference for the start & end dates. I have included them in my solution, but with a number of assumptions.
In any case, here's the sql
SET #startdate:='2012-12-24 17:00:00';
SET #enddate:='2013-01-02 12:00:00';
SELECT
TIME_TO_SEC(TIMEDIFF(CONCAT(DATE(#startdate),' 17:30:00'), #startdate))/3600 as startday_time,
TIME_TO_SEC(TIMEDIFF(#enddate, CONCAT(DATE(#enddate),' 9:00:00')))/3600 as endday_time,
SUM(daily_hours) as otherdays_time from
(
SELECT 7.5 as daily_hours, id, DATE_ADD(DATE(#startdate),INTERVAL id-1 DAY) as idate from numbers
) dates
LEFT JOIN holidays on DATE(dates.idate) = DATE(holidays.date)
WHERE
idate BETWEEN #startdate AND #enddate
AND holidays.date IS NULL
AND DAYOFWEEK(idate) <> 7 AND DAYOFWEEK(idate) <> 1;
sqlfiddle here:
http://sqlfiddle.com/#!2/ff3f3/1/2
To get the valid interim dates, we'll need two tables - a holidays table listing all the holiday dates and a numbers table that contains a series of integers which is very useful for joining against to get a sequential series of dates (with no gaps).
Note: In the sqlfiddle, I've populated the numbers table only up to 12 to cover the dates used in my example - it will probably need to be populated to a higher number depending on the range of dates you'll be working with.
For the start day time & end day time, I've made the following assumptions:
that start date & end date are both valid dates that should be counted towards the total time
that the time on the start date is between lunch and 17.30
that the time on the end date is between lunch and 17.30
if these assumptions are wrong, you're getting into serious conditional territory (with lots of ifs) and might be best doing this in the php (or whatever).
note: I've left the times (which are in hours) un-added for illustration purposes.