I have a report that, according to users, started miscalculating dates in one field in November 2015. After some digging around, I found that one of the tables the field referenced seemed to have an end date on 2015-10-31.
The "D" field seems to represent the day of the week, with Sunday being day 1 and Saturday being 7.
Is there a way to extend the calendar so that it ends further into the future, for example 2049-12-31?
Our calendar table, for a variety of reasons, goes the the end of the current year. We have written a query that adds a new year to this table. This query takes care of most of the fields in that table. It does not touch the holiday field. That is updated manually through a web page.
We send ourselves reminders. Starting in March, we send monthly reminders that we should think about adding another year. After ensuring that the database segment has space, and that none of the definitions, such as fiscal periods, have changed, we run the query that adds a year.
Later in the year we start mailing ourselves reminders about the holidays. Then we check to see if HR has declared them, and if so, update the records accordingly.
This meets our business requirements. Yours will be different of course.
Related
Problem overview
I'm working on a simple app for reminding the user of weekly goals. Let's say the goal is to do 30 minutes of exercise on specific days of the week.
Sample goal: do exercise on Mon, Wed, Fri.
The app also needs to track past record, i.e. dates when the user did exercise. It could be just dates, e.g.: 2019-09-02, 2019-09-05, 2019-09-11 means the user did exercise on these days and did not on the others (doesn't need to be on "exercise goal" days of the week).
The goal can change in time. Let's say today is 2019-09-11 and the goal for this week ([2019-09-09, 2019-09-15]) is Mon, Wed, Fri but from 2019-08-05 to 2019-09-08 it was Mon, Thu (repeatedly for all these weeks).
I need to store these week-oriented goals and historic exercise of data and be able to retrieve the following:
The goal days for the current week (or any week, let's say I can compute start and end day for any week given a date).
Exercise history for a larger range of days together with goal days for that range (e.g. to show when the user was supposed to exercise and when they actually did in the last month).
Question
How to best store this data in SQL.
This is a little bit academic because I'm working on a small Android app and the data is just for a single user. So there will be little data and I can successfully use any approach, even a very clumsy one will be efficient enough.
However, I'd like to explore the topic and maybe learn a thing or two.
Possible solutions
Here are two approaches that come to my mind.
In both cases I would store exercise history as a table of dates. If there is an entry for that date it means the user did exercise on that day.
It's the goal storage that is interesting.
Approach 1
Store the goals per-week (it's SQLite so dates are stored as strings - all dates are just 'YEAR-MONTH-DAY'):
CREATE TABLE goals (
start_date TEXT,
exercise_days TEXT);
"start_date" is the first day of the week,
"exercise_days" is a comma-separated list of weekdays (let's say numbers 1-7).
So for the example above we might have two rows:
'2019-08-05', '1,4'
'2019-09-09', '1,3,5'
meaning that since 2019-08-05 the goal is Mon, Thu for all weeks until 2019-09-09, when the goal becomes Mon, Wed, Fri. So there is a gap in the data. I wouldn't want to generate data for weeks starting on 2019-08-12, 2019-08-19, 2019-08-26.
With this approach it is easy to work with the data week-wise. The current goal is the one with MAX('start_date'). The goal for a week for a given date is MAX('start_date') WHERE 'start_date' <= :date.
However it gets cumbersome when I want to get data for the last 3 months and show the user their progress.
Or maybe I want to show the user the percentage of actual exercise days to what they set as their goal in a year.
In this case it seems the best approach is to fetch the data separately and merge it in the application (or maybe write some complex queries), processing week by week. This is ok performance-wise because the amount of data is small and I rarely need more than a handful of weeks.
Approach 2
Store goals in such a way that each goal day is a record:
CREATE TABLE goals (
day TEXT,
);
"day" is a day when the user should exercise. So for the week starting 2019-09-09 (Mon, Wed, Fri) we would have:
'2019-09-09'
'2019-09-11'
'2019-09-13'
and for the week starting 2019-08-05 (Mon, Thu) we would have:
'2019-08-05'
'2019-08-09'
but what for the weeks in-between?
If my app could fill all the weeks in-between then it would be easy to merge this data with the exercise history and display days when the user was supposed to exercise and when they actually did. Extracting the goal for any given week would also be easy.
The problem is: this requires the app to generate data for the "gap" weeks even if the user doesn't tweak the goal. This can be implemented as a transaction that is run each time the app process starts. In some cases it could take noticeable time for occasional users of the app (think progress bar for a second).
Maybe there a smart way to generate the data in-between when making a SELECT query?
I don't like the fact that it requires generating data. I do like the fact that I can just join the tables and then process that (e.g. compute how many exercise days there were supposed to be in August and how many days the user did actually exercise and then show them percentage like "you did 85% of your goal" - in fact I can do this without joining the tables).
Also, it seems this approach gives me more flexibility for analysis in the future.
But is there a third way? Or maybe I am overthinking this? :)
(I am asking mostly for the way of organizing the data, there's no need for exact SQL queries)
Perhaps I'm over-thinking this, but if a goal can have multiple components to it, and can change over time I'd have a goal header record, with the ID, name and other data about the goal as a whole, and then a separate table linked with the components of that goal which are time-boxed, for example:
CREATE TABLE goal_days (goal_day_ID INT,
goal_ID INT,
day_ID INT,
target_minutes INT,
start_date TEXT,
end_date TEXT)
I'd have thought that allows you to easily check against the history to map against each day of the goal - e.g. they got 100% of the Mondays, but kept missing Thursday - however when the goal was changed to Friday instead they got better.
I have a challenge ahead of me. I have looked at this for a couple of days now in a trial and error sense and am getting tired of not getting it… My SQL knowledge is very very basic.
Each quarter I have to report on the questions below (of course the date period changes):
The number of doctors with whom the designated body has a prescribed connection at 31st December.
The number of doctors due to hold an appraisal meeting in the reporting period (from 1st October to 31st December 2017).
The number of those doctors above who held an appraisal meeting in the reporting period.
The number of those doctors above who did not hold an appraisal meeting in the reporting period.
I have three lists:
A list of staff responsible to the designated body. In a linked table- ‘GMC_Main’ Field- GMC Ref No
A list of all appraisals that have ever taken place (historical and ones performed by staff not responsible to us). In a query called-
‘Latest Appraisal’ Fields- ProfNum, MaxOfAppDate
List of emails in a linked table- ‘MARS_Core’ Fields- ProfNum, EmpSurname, EmpFirstName, EmpEmail
Things to consider
ProfNum and GMC Ref No are the Unique identifiers for each member of
staff.
GMC_Main is the list of all staff that need to be considered in the
report. So should have a row regardless of the results from the other
tables.
All appraisals are valid for 365 days. So The date 1 year in the future from that in MaxofAppDate will be needed to calculate expiry in the period.
Due to software limitations I only have available Access 2016.
I need to count all that should have taken place, including ones that
are still overdue from previous quarters.
Count all the ones that actually took place in the period.
Be able to contact all the ones that did not achieve and appraisal.
At year end (31 March) do this for the entire year and not just the
quarter…
Fuff!
Each time I approach this problem I am missing a group of people or feel I am doing it in a very wrong-handed way.
If anyone could help, then that would be amazing. This is a little beyond me.
I want to have a function to return the next business day of the date that is sent in as parameter.
Weekends and Canadian holidays should be included.
What is the easiest way to do this ? Is it possible to do this without setting a reference to a range of cells for the holidays' dates?
Unless you provide a list of holidays, you won't be able to calculate the next working date. Remember the rules for Easter involve the phase of the moon! So this is not a simple task.
That is before you start to consider which different countries. Even if you restrict yourself to the US holidays, it takes a fair bit of calculations just to get the 3rd Thursday in November etc
Here is a demonstration of how you could calculate the next working day.
I wouldn't hold just the holidays but every date in the calendar. Note for Easter I have fudged the holiday column to get the correct next working day answer.
You could miss a few steps in the calculation, I left them in for clarity.
Use the =WORKDAY() function. You'll have to specify a range of holidays as the third parameter.
I'm developing a c# application that consists of Document Incoming System for my police station.
In this system, variable document's contents are been saved to an SQL database. I must give them a "Document Number".
I'm achieving all of these, but i want that every years last day such as 31.12.2014, the numbers that have been given to a document like "2145" will turn to "1" at the the first day of year 01.01.2015.
So, the records must be 2014/2145. and the last days of years turns to 2015/1.
How can I achieve this?
You count the existing documents for the same year, then add one.
So if you want to store a document that belongs to 2013, you first count how many existing documents you have in 2013, then add one.
I can't write the sql for you, because you haven't described the data structure, but it should be simple enough using SQL COUNT, and DATEPART to retrieve only the year from a date field.
I have to create "holiday" table and then create php script so I could show it on my site.
Holidays can be specific, like 15.05.2012 - 15-th of the may.
And non-specific: First(or second, third) sunday of july
Is there any way to create calculated column, so this phrase "First(or second, third) sunday of july", could turn into x.07.2012.
Use a calendar table. There is no magic code built into SQL Server that knows when Easter is. This article shows the basic premise - you fill up a table with all the dates from year x to year y, then you update a column called IsHoliday for the dates that are holidays based on specific logic (easiest to do this once, in a loop, then all your code later can refer to the calculated bit):
ASP Faq reference. The current link no longer works, this is the archive.org cached version of the page
The link in the answer now takes you to a bogus page that wants to load a virus. Just heads up.
http://codeinet.blogspot.com/2006/08/auxiliary-calendar-table-for-sql.html
This seems to be a working version.