Database design - how can I have a recurring database entry? - sql

I am currently using the FullCalendar JQuery module to allow a user to create a personal timetable. The events are added/updated to an SQL Server database. This is working fine.
I am trying to create a facility where each user has a database which has stored all of their events for the year, some of which can be recurring and occur every week.
I then wish to have users be able to organize meetings with other users based on the timeslots available in their timetables.
I'm not sure how to integrate these recurring events into my system, or how my algorithm would work with these recurring events.
The design I have at the moment is :
CREATE TABLE Users (
user_id INT NOT NULL AUTO_INCREMENT,
email VARCHAR(80) NOT NULL,
password CHAR(41) NOT NULL,
PRIMARY KEY (user_id)
);
CREATE TABLE Events (
event_id INT NOT NULL AUTO_INCREMENT,
title VARCHAR(80) NOT NULL,
description VARCHAR(200),
start_time DATETIME,
end_time DATETIME,
group_id INT NOT NULL,
recurring boolean
);
CREATE TABLE Groups (
group_id INT NOT NULL,
user_id INT NOT NULL
);
Will this be sufficient? How will I have it so that recurring events are rendered on the calendar for every week? If I am lacking in any detail, please ask! Thank you very much.

You could use something like the following:
SELECT *
FROM Events
WHERE Recurring = 0
UNION
SELECT Event_ID,
Title,
Description,
DATEADD(WEEK, Interval, Start_Time) [Start_Time],
DATEADD(WEEK, Interval, End_Time) [End_Time],
Group_ID,
Recurring
FROM Events,
( SELECT ROW_NUMBER() OVER(ORDER BY Object_ID) [Interval]
FROM SYS.ALL_OBJECTS
) i
WHERE Recurring = 1
AND Interval <= 52 -- reccurs for 1 year
This will make all events repeat for 52 weeks (or whatever period you want).
As an aside, in the question you mentioned sql server, and you have tagged the question as SQL server but all your syntax appears to be MySQL (AUTO_INCREMENT, Boolean data type).

Related

Time period SQL view

I am trying to create a SQL view on two tables I'm working with:
CREATE TABLE availability
(
doctor varchar(20) NOT NULL,
avl_date date NOT NULL,
avl_start time NOT NULL,
avl_end time NOT NULL,
CONSTRAINT pk_availability PRIMARY KEY (doctor, avl_date)
);
And
CREATE TABLE appointments
(
patient varchar(20) NOT NULL,
doctor varchar(20) NOT NULL,
apt_date date NOT NULL,
apt_start time NOT NULL,
apt_end time NOT NULL,
CONSTRAINT pk_appointments PRIMARY KEY (patient, apt_date)
);
The view I am trying to create lists all maximal time periods (apt date, apt start, apt end) during which no further appointments are possible (consider doctors’ availability as well).
Any help is greatly appreciated, thanks.
this should work if the appointment time-duration is constant. You can optimize it by re-writing with inner join instead of minus. Also, remember to put availability table above minus.
select doctor
, avl_date
, avl_start
, avl_end
from availability
minus
select doctor
, apt_date
, apt_start
, apt_end
from appointments

Get all information about a person from when he or she was XX years old

I store a person's birthday as DATE in the database. If I go to the page /person/10/age/25, I want to get all data for this person that are from when he or she was 25 years old, based on his or hers birthday.
Currently, I'm using FLOOR(DATEDIFF(CURRENT_DATE, STR_TO_DATE(date_birth, '%Y-%m-%d')) / 365.25) to get the age of the person based on DATE. But I want to some how reverse this formula (correct word?) so it is getting all the information about the person, from when he or she was 25 years old.
SQL query:
SELECT *
FROM images AS i
JOIN people AS p
ON i.id_person = p.id
WHERE p.id = '10'
# new line
AND i.date_taken = DATE_ADD(p.date_birth, INTERVAL 25 YEAR)
# old line
# AND p.date_birth = FLOOR(DATEDIFF(CURRENT_DATE, STR_TO_DATE(date_birth, '%Y-%m-%d')) / 365.25)
Here's how the database looks like:
CREATE TABLE IF NOT EXISTS `images` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_person` int(11) NOT NULL,
`date_taken` date DEFAULT NULL,
UNIQUE KEY `id` (`id`)
);
CREATE TABLE IF NOT EXISTS `people` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`data_name` tinytext NOT NULL,
`date_birth` date NOT NULL,
UNIQUE KEY `id` (`id`)
)
http://sqlfiddle.com/#!9/6d1cfc/2
How can I accomplish this?
First up: don't do date manipulation this way (especially using 365.25 as a year multiplier) Instead, take a look at the DateAdd function.
(Ugh, had a long post typed out, and only after posting noticed that you're in MariaDB instead of MSSQL)
Anyway, you're looking for something like:
DATEADD(dateOfBirthValue, INTERVAL 25 YEAR)
... this will add 25 years to a specific date value. Hope that helps - I can't really post a code snippet because I'm not familiar with the ins-and-outs of MariaDB (but I do know that you're going to want to use DateADD instead of manually calculating out days.)

Storing Schedule Information

I need to create a table to hold a schedule for meetings.
A meeting can be scheduled to be:
Daily
'Ever X days'. where X can be between 1 and 6.
Ending after X sessions. Where 'sessions' is basically the number of repeats.
Weekly
Which days during the week it can occur. Mon, Tue, etc. Can select more than one day per week.
The Date on which it ends.
Monthly
Use can select the day of the month it can occur (1st, 2nd etc)
OR they can select from a lookup of '1st, 2nd, 3rd, 4th or Last' and a Day 'Mon, Tues', saying, for example "The 2nd Friday" of the month.
How can I store all these scenarios in a single table?
I was thinking:
CREATE TABLE schedule
(
ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
StartDate DATETIME NOT NULL,
EndTime TIME NULL,
RepeatTypeID INT NOT NULL, // Daily, Weekly, Monthly, None
// For Daily
EveryDayCount INT NULL, // to handle 'every 3 days',
RepeatCount INT NULL, // How many occurances. Can be shared with different RepeatTypes
// weekly
IsMonday BIT,
IsTuesday BIT,
etc // A field per day selection. Is there a better way?
// Monthly
MonthlyDayNumber INT NULL,
MonthlyRepeatIntervalID INT, // Lookup table with '1st, 2nd, 3rd, 4th, Last'
MonthlyDayRepeatSelection INT // Lookup on Monday, Tuesday etc
)
But this seems inefficient. Is there a better design pattern for these sorts of requirements?
So basically I once implemented the same functionality and I found that rather than ease of storage, that ease of retrieval and edit/update was of paramount importance.
You don't want to calculate all dates every single time, you query the DB for meeting dates or say like you have a function like showAllMeetingsForADate(somedate date) then you would not want to calculate dates for meeting at run time.
Holistically the most optimal storage is that you store meeting information calculation logic in a table and all meeting dates in another table like below.
However for the storage of meeting information, you should go with a normalized form.
Schedule Detail Tables
CREATE TABLE DailyScheduleDetails
(
ScheduleDetailsID INT PRIMARY KEY IDENTITY(1,1),
RecurrenceCount INT NOT NULL
)
CREATE TABLE WeeklyScheduleDetails
(
ScheduleDetailsID INT PRIMARY KEY IDENTITY(1,1),
OnMonday bit,
OnTuesday bit,
OnWednesday bit,
-- ...
OnSunday bit,
EndByDate Date NOT NULL
)
CREATE TABLE MonthlyScheduleDetails
(
ScheduleDetailsID INT PRIMARY KEY IDENTITY(1,1),
MonthlyDayNumber INT NULL,
MonthlyRepeatIntervalID INT, // Lookup table with '1st, 2nd, 3rd, 4th, Last'
-- Here I'd suggest using 0 for Last
MonthlyDayRepeatSelection INT // Lookup on Monday, Tuesday etc
)
Schedule
CREATE TABLE schedule
(
ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
StartDateTime DATETIME NOT NULL,
EndDateTime DATETIME NULL,
RepeatTypeID INT NOT NULL, // Daily, Weekly, Monthly, None
ScheduleDetailsID INT
)
MeetingDates
CREATE TABLE MeetingDates
(
ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
MeetingID int,
MeetingStartDate datetime,
MeetingEndDate datetime -- because you can have meeting spanning days like 11:00 PM to 1:00 AM
--,user or guest information too
,CONSTRAINT FK_MeetingDates_Schedule FOREIGN KEY (MeetingID)
REFERENCES Schedule(ID)
)
Use an existing standard. That standard is iCalendar RRules and ExDates.
Just store the recurrance rule in the db as a varchar
Use an existing library (C#) to calculate upcoming dates
Even though you have daily, weekly, monthly etc... still means that a meeting will occur on some specific day ... right ?
Thus
CREATE TABLE schedule
(
ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
StartDate DATETIME NOT NULL,
EndDate DATETIME NOT NULL,
RepeatTypeID INT NOT NULL, // Daily, Weekly, Monthly, None
RepeatCount INT NOT NULL,
DayOn INT NOT NULL, // can be a calculated field based on start date using DAY function
)
I believe this can capture all your schedule options.

SQL DDL - 2 CHECK Constraints on 1 Attribute

Below is DDL for the table I want to create. However, I want the attribute 'Appointment_datetime' to be a future date and during working hours (between 8:00AM and 5:00PM). I can get the future date part with -'CHECK (Appointment_datetime >= GETDATE()) But how do I get between 8AM and 5PM ontop of this constraint?
CREATE TABLE tAppointment
(
Appointment_ID int NOT NULL PRIMARY KEY,
Appointment_datetime datetime NOT NULL, -- CHECK CONSTRAINTS NEEDED
Appointment_week int NOT NULL,
Appointment_room varchar(5) NOT NULL,
Vet_ID int NOT NULL REFERENCES tVet(Vet_ID),
Owner_ID int NOT NULL REFERENCES tOwner(Owner_ID),
Pet_ID int NOT NULL REFERENCES tPet(Pet_ID)
)
You can just add it in. Here is a method using the hour:
CHECK (Appointment_datetime >= GETDATE() AND
DATEPART(HOUR, GETDATE()) NOT BETWEEN 8 AND 16
)
Note: If you want to take weekends and holidays into account, that is more difficult and probably requires a user-defined function.

Beginner with triggers

Im a beginner in database and i got this difficult auction database project.
Im using SQL Server Management Studio also.
create table user(
name char(10) not null,
lastname char(10) not null
)
create table item(
buyer varchar(10) null,
seller varchar(10) not null,
startprice numeric(5) not null,
description char(22) not null,
start_date datetime not null,
end_date datetime not null,
seller char(10) not null,
item_nummer numeric(9) not null,
constraint fk_user foreign key (buyer) references user (name)
)
Basically what the rule im trying to make here is:
Column buyer has NULL unless the time (start_date and end_date) is over and startprice didnt go up or increased. Then column buyer will get the name from table user who bidded on the item.
The rule is a bid too difficult for me to make, i was thinking to make a trigger, but im not sure..
Your model is incorrect. First you need a table to store the bids. Then when the auction is over, you update the highest one as the winning bid. Proably the best way is to have a job that runs once a minute and finds the winners of any newly closed auctions.
A trigger will not work on the two tables you have because triggers only fire on insert/update or delete. It would not fire because the time is past. Further triggers are an advanced technique and a db beginner should avoid them as you can do horrendous damage with a badly written trigger.
You could have a trigger that works on insert to the bids table, that updates the bid to be the winner and takes that status away from the previous winner. Then you simply stop accepting new bids at the time the auction is over. Your application could show the bidder who is marked as the winner as the elader if the auction is till open and teh winner if it is closed.
There are some initial problems with your schema that need addressed before tackling your question. Here are changes I would make to significantly ease the implementation of the answer:
-- Added brackets around User b/c "user" is a reserved keyword
-- Added INT Identity PK to [User]
CREATE TABLE [user]
(
UserId INT NOT NULL
IDENTITY
PRIMARY KEY
, name CHAR(10) NOT NULL
, lastname CHAR(10) NOT NULL
)
/* changed item_nummer (I'm not sure what a nummer is...) to ItemId int not null identity primary key
Removed duplicate Seller columns and buyer column
Replaced buyer/seller columns with FK references to [User].UserId
Add currentBid to capture current bid
Added CurrentHighBidderId
Added WinningBidderId as computed column
*/
CREATE TABLE item
(
ItemId INT NOT NULL
IDENTITY
PRIMARY KEY
, SellerId INT NOT NULL
FOREIGN KEY REFERENCES [User] ( UserId )
, CurrentHighBidderId INT NULL
FOREIGN KEY REFERENCES [User] ( UserId )
, CurrentBid MONEY NOT NULL
, StartPrice NUMERIC(5) NOT NULL
, Description CHAR(22) NOT NULL
, StartDate DATETIME NOT NULL
, EndDate DATETIME NOT NULL
)
go
ALTER TABLE dbo.item ADD
WinningBidderId AS CASE WHEN EndDate < CURRENT_TIMESTAMP
AND currentBid > StartPrice THEN CurrentHighBidderId ELSE NULL END
GO
With the additional columns a computed column can return the correct information. If you must return the winner's name instead of id, then you could keep the schema above the same, add an additional column to store the user's name, populate it with a trigger and keep the computed column to conditionally show/not show the winner..