How to structure MySQL daily checklist database - mysql

I am trying to create a database application for daily task. I am converting a paper form I use.
Each row is a task and each column is a date. Every day I go through and complete the task and initial the cell that corresponds with the date. But not every task is required daily. I included an example of how it will appear in the browser.
How do I structure the database?

You could do:
TasksDefinition
Id PK
TaskName NN
TasksWhen
Id PK
TaskId FK, TasksDefinition.id
Day NN --> what day should task Id be completed
History
Id PK
TaskId FK, TasksDefinition.Id
Date NN
Done NN, boolean, default False
PK: primary key
FK: foreign key
NN: not null
Each task is defined in TasksDefinition
TasksWhen stores the information on what day(s) should each task be completed. One entry per task/day of the month (ex. 1 to 31). OR 0-6 if you want to use week days. Using a table allows you to have some tasks completed on many days. Ex. for task X, on day 1, 4, and 28 would require 3 entries in TasksWhen.
At 0001 each day, your application does:
Add each tasks that have to be completed that day to the History table, with the current date and Done == False.
When you have completed the task, change History.Done to True.
When you build your interface, you query the history table only. This will give you which tasks have been done (or not) on each day. The status of completion goes to the History table as well.
You can use day of month or week day to specify which tasks must be done on each day. You could even use a mix of both. As long as your application can figure it out, you would be fine.
The monthly report is built from data in the history table.

Related

Mysql Function multiple entries in one cell

So I'm working on a schedule system for my job a basically i wanted to know if there is a way where mysql can do something like:
|Monday |tuesday|wendsday|total
|Dan |5am-7am |7am-6pm|6am-11am|
11am-2pm| |2pm-7pm |
5pm-12am|
where i can enter multiple shifts on 1 day for each person in the same cell if needed instead of the name repeating several times like:
Dan|5-4|
Dan|6-8|
and if there is a function to calculate total time in one cell with multiple shifts
There is a way (representing the data as string), but you wouldn't want to do this - you will loose all calculations, searches etc.
You should not try to represent the data in the database exactly as how it looks on paper.
I would make a table like this:
ShiftID|Person|StartTime|EndTime
Making StartTime & EndTime columns of type DATETIME, you will store not only the HH:mm of a shift's start, but also the day. This is helpful when you have a shift which starts on one day and ends in the next, like starting on Monday 2017-05-15 23:00 and ending on Tuesday 2017-05-16 02:00.
You can extract the date only from this filed using MySQL DATE() function and select only those entires which start OR end on this day.
To calculate the shift's duration you can use MySQL function TIMESTAMPDIFF()
You can even use DAYOFWEEK() to get if it is Monday, Tuesday, etc.
About duplicating the person's name - I would make another table, which will match users with their data to IDs an use ID in the column Person, but for a starter and if your data is not big and if speed is not an issue and if typo errors (like Den instead of Dan) are not a problem ... you could use the name directly in this table.
After storing the data in a table like this you could represent it as you wish in HTML (or print).
You can create a third table with the following columns:
person_id int,
start_time datetime,
end_time datetime
Where person_id would be foreign key to Person table and start_time and end_time would be datetime columns. You can then store multiple records for a person in this table and use MySQL's date functions with GROUP BY to generate the report similar to the one in question.

Need better database design approach

I have designed a database schema for a subscription product. user can select subscription starting from a date for certain amount of days. User can cancel a subscription for some days while still keeping the subscription active afterwards. meaning if user subscribes for a month she can cancel it on days say 10,15 and 20 thus paying for only 27 days (30 minus 3).
So far I have come up with this schema.
each user has one profile.
user can select a plan.
once user selects a plan it is noted as transaction which also stores information about start date and duration of that plan.
each transaction has payment (focusing on that part later)
Now, since user can cancel subscription any day how should I keep track of different users and days on which they had subscription?
The solution that I have in mind is crate a new table Plan_Transaction_user which will keep track of each date and transaction ID for that date. This way If user cancels her subscription on particular date there will be no record of that date for that transaction ID.
table will look like this:
Date Transaction ID
1-1-2017 1
1-1-2017 2
1-1-2017 3
1-2-2017 1
1-2-2017 3
Since user associated with transaction_id 2 cancelled for day 2 her transaction record is not present in this table.
Now if I have customer base of say 5000 then in best case within one year I will have 5000 * 365 ~ 1.8m rows. I am sure this is not best approach to go about it. Could you please suggest me any better schema or some changes in existing schema which can be more efficient? Just in case you want to know I will be using MariaDB (AWS RDS) as a database and Python 2 as my language.
Thank you,
Ojas
You can add a end_date field in Transaction table instead of duration. You can easily defined end_date as start_date + how many days you will given for selected plan. When user cancel some days then you can reduce end_date as end_date = end_date - number of cancel days. You can check how many valid subscription currently at any days checking through end_date >= today.
Similar to your Plan_Transaction_user design, if u only need to know how many subscribers for any particular date, but not who they are, u can aggregate the table by day. Like
Date user_count
1-1-2017 1
1-2-2017 2

MySQL - Get missing entries in a date range

I have a table with the following structure:
Entry ID | Date | Approved
Whenever a new entry is made, Entry ID auto increments and date is set to whenever the entry was made through the web application. These entries are not necessarily made every day, so there are gaps between dates.
I need to find all "missing" entries, meaning that there is no entry for that date. For instance, if there was an entry for 2015-06-01 and the next one didn't come until 2015-06-07, I need a query that returns the list of dates from 2015-06-02 to 2015-06-06 and an indication of their approved status from that field. I've been looking for a while but can't seem to find a method to get a list of entries that don't exist. Is there a method for this, or should I restructure?
Create a temp table with all possible dates and do
SELECT Date FROM temp_table WHERE Date NOT IN (SELECT Date FROM your_table);

Mysql performance selecting blog post views by date

Question about SQL performance when selecting a 'blog post' based on user views by date.
I want to record the user views of each post, and i ll select everyone of them using 'daily' and 'monthly' as parameters:
PS:
Most viewed posts of the day, or month.
To record the views, i created a table to insert, after every page load, the date of each view.
And them select them (count them) by DAY() and MONTH() when needed.
The problem here is, when the table or the amount of users requiring this information grows the select starts to be slower, due to the amount of rows(views) multiplied for the amount of posts.
One alternative that i thought was, create a table for daily records, and another table for monthly records, then on every page load the code checks if there is a row for the selected date, if the rows exist the script increment the views count on it, if it doesn't, the script insert the row with views count = 1;
Ps:
Daily Views
Post ID | Views | Date
1 | 898 | 2014-07-11
2 | 676 | 2014-07-11
1 | 333 | 2014-07-10
This way every post can have only one row per day.
Is there any better option? what do you think about my alternative? there is no need for my suggestion?
I think the best solution is:
Create a table with statistical data with fields:
id
date (store date m-d-y)
day
month
year
views (store number of visits)
page (store blog post)
One unique row per day, and update programmatically as needed.
Then you can make queries using day, month, year fields, even you can add weeknum field to make queries to obtain statistics grouped by weeks.
As addition you can add a second table to store the full date (m-d-y h:m:s) for each visit, you can add fields like browser, ip, etc... to this table.

MySQL Hibernate sort on 2 columns

I have a table as follows
Table item {
ID - Primary Key
content - String
published_date - When the content was published
create_date - When this database entry was created
}
Every hour (or specified time interval) I run a process to update this table with data from different sources (websites). I want to display the results according to the following rules.
1. The entries created each time the process runs should be grouped together. So the entries from the 2nd process run will always be after the entries from the first process run even if the published_date of an entry from the first run is after the published_date of an entry from the 2nd run.
2. Within the grouping by run, the entries by sorted by published_date
3. Another restriction is that I prefer that data from the same source not be grouped together. If I do the sort by create_date, published_date I will end up with data from source a, data from source b etc. I prefer that the data within each hour be mixed up for better presentation
If I add a column to this table and store a counter which increments each time the process is run, it is possible to create a query to sort first by counter and then by published_dt. Is there a way to do it without adding a field? I'm using Hibernate over MySQL.
e.g.
Hour 1 (run 1)
4 rows collected from site a (rows 1-4)
3 rows collected from site b (rows 5-7)
hour 2 (run 2)
2 row collected from site a (rows 8-9)
3 rows collected from site b (rows 10-12)
...
After each run, new records are added to the database from each website. The create date is the time when the record was created in the database. The published date is part of the content and is read in from the external source.
When the results are displayed I would like rows to be grouped together based on the hour they were published in. So rows 1-7 would be displayed before rows 8-12. Within each hourly grouping, I would like to sort the results by published date (timestamp). This is necessary so that the posts from all the sites collected in that hour are not grouped together but rather mixed in with each other.
If you add a counter, you can definitely order items by counter first and then published date:
from Item item order by item.counter desc, item.publishedDate