SQL DDL - 2 CHECK Constraints on 1 Attribute - sql

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.

Related

How do I validate these columns, do i need more complex triggers?

I'm trying to validate the columns in the table ProjectDetails.TimeCards
create table ProjectDetails.TimeCards(
Time_Card_ID int identity (55,15),
Employee_ID int foreign key references HumanResources.Employees(Employee_ID),
Date_Issued date, --DateIssued should be greater than the current date and the project start date (Project start date is from another table).
Days_Worked int constraint chk_Days_Worked check(Days_Worked > '0'),
Project_ID int foreign key references ProjectDetails.Projects(Project_ID),
Billable_hours int constraint chk_Billable_Hours check (Billable_Hours > '0'),
Total_Cost money, -- should be automatically calculated by using the following formula: TotalCost=Billable Hours * BillingRate (billing rate is from another table)
Work_Code_ID int foreign key references ProjectDetails.WorkCodes(Work_Code_ID)
);
I tried building a trigger, but was only able to get the trigger to fire if the Date_Issued was less than the current date
CREATE TRIGGER dateissued
ON ProjectDetails.TimeCards
FOR INSERT
AS
DECLARE #ModifiedDate date
SELECT #ModifiedDate = Date_Issued FROM Inserted
IF (#ModifiedDate < getdate())
BEGIN
PRINT 'The modified date should be the current date. Hence, cannot insert.'
ROLLBACK TRANSACTION -- transaction is to be rolled back
END
i need the trigger to fire if the Date issued is less than the current date and also if date issued is less than the start_date. As for the billing rate calculation i'm lost there.
This is the other table
create table ProjectDetails.Projects(
Project_ID int identity (0100, 01) primary key, -- Primary key
Project_Name char (50) not null,
Start_Date date not null, -- the start date i'm referring to
End_Date date not null,
constraint CheckEndLaterThanStart check (End_Date > Start_Date),
Billing_Estimate money constraint chk_Billing_Estimate check (Billing_Estimate > '1000'),
Client_ID int Foreign Key references CustomerDetails.Clients(Client_ID)
);
I believe this provides the logic you are after. There are a couple of comments in the code for you:
CREATE TRIGGER trg_chk_Date_Issued ON ProjectDetails.TimeCards
FOR INSERT, UPDATE --I assume on need on UPDATE as well, as otherwise this won't validate
AS BEGIN
IF EXISTS(SELECT 1
FROM inserted i
JOIN ProjectDetails.Projects P ON i.Project_ID = P.Project_ID
WHERE i.Date_Issued < CONVERT(date,GETDATE())
OR i.Date_Issued < P.Start_Date) BEGIN
RAISERROR(N'Date Issued cannot be less than the current date or the Project Start Date.', 10,1); --Raised an error, rather than using PRINT
ROLLBACK;
END
END
Note that you may want a different trigger for UPDATE, as if you are updating the row, and Date_Issued has a value lower than the date of the UPDATE, the statement will fail.

How to update a column based on an amount of time in SQL

I want to create a stored procedure to update a column based on an amount of time. For example, to update the interest generated column every 15 days.
Here is my code. Please help.
create table Loan(
Loan_ID int not null primary key,
Loan_custID int not null foreign key references Customers(Cust_ID),
Loan_Amount int not null,
Loan_Interest int not null,
Loan_Date date not null unique,
)
Create table Interestgenerated(
IG_ID int not null primary key,
Loan_ID int not null foreign key references Loan1(Loan_ID),
Loan_Date date null foreign key references Loan1(Loan_Date),
IG_Amount int not null,
IG_Date datetime not null
)
create procedure InsertINtoInterestgenerated1
#PresentDate Datetime
as
set #PresentDate=getdate()
select Loan_ID from Loan
set IG_Date=Loan_Date
IG_Date=dateadd(day,15, IG_Date)
if #PresentDate=IG_Date
begin
update Interestgenerated1 set IG_Date = #PresentDate, IG_Amount=IG_Amount*0.15
end
Considering you want to automate the update of the value in column IG_Amount every 15 days,
you can schedule a job to run every 15 days at midnight like on the 1st and 16th of every month.
the below link might help you:
how to schedule a job for sql query to run daily?

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.

Constraint to check if time greater than 9 am

How to check time entry only so that any entry before is not acceptable?
CREATE TABLE demo.event(
ecode CHAR(4) UNIQUE NOT NULL PRIMARY KEY,
edesc VARCHAR(20) NOT NULL,
elocation VARCHAR(20) NOT NULL,
edate DATE NOT NULL
CONSTRAINT date_check CHECK(edate BETWEEN '2016/04/01' AND '2016/04/30'),
etime TIME NOT NULL
CONSTRAINT time_check CHECK(etime (HOUR > '08:00:00')),
emax SMALLINT NOT NULL
CONSTRAINT emax_check CHECK(emax >=1 OR emax<=1000)
);
The above code gave me an error
ERROR: column "hour" does not exist
To write a time literal, you need to use the keyword time not hour:
CONSTRAINT time_check CHECK(etime > TIME '08:00:00'),
so any entry before 9:00 am not acceptable.
contradicts the 08:00:00' you have used, > TIME '08:00:00' will allow 08:00:01 (one second after 8am). If you really only want to allowed values after 9am, then use:
CONSTRAINT time_check CHECK(etime > TIME '09:00:00'),
You should also use proper ISO formatted dates to avoid any ambiguity:
CONSTRAINT date_check CHECK(edate BETWEEN DATE '2016-04-01' AND DATE '2016-04-30')
More details on the proper syntax for date and time literals can be found in the manual:
http://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-INPUT

Complex T-SQL Statement

I am not the best SQL programmer so I am basically asking someone for help writing a query that will get my desired result. Here is the table structure for the scope of the query.
CREATE TABLE [dbo].[tblOverNightPermissions] (
[DateAndTime] DATETIME NULL,
[Address] NVARCHAR (200) NULL,
[Direction] NVARCHAR (102) NULL,
[NoOfDays] INT NULL,
[UserID] INT NOT NULL,
[OverNightID] INT IDENTITY (1, 1) NOT NULL,
[Exempt] INT NULL,
[Beat] INT NULL,
CONSTRAINT [PrimaryKey_1fd244dd-bfd8-4998-8439-4d7d7893d387] PRIMARY KEY CLUSTERED ([OverNightID] ASC),
CONSTRAINT [FK_tblOverNightPermissions_0] FOREIGN KEY ([UserID]) REFERENCES [dbo].[tblUsers] ([UserID])
);
CREATE TABLE [dbo].[tblOverNightToVehicles] (
[OverNightID] INT NOT NULL,
[VehicleID] INT NOT NULL,
[ID] INT IDENTITY (1, 1) NOT NULL,
CONSTRAINT [PrimaryKey_b433eaad-fb12-493c-9302-3f3bd9bd74e3] PRIMARY KEY CLUSTERED ([ID] ASC),
CONSTRAINT [FK_tblOverNightToVehicles_0] FOREIGN KEY ([OverNightID]) REFERENCES [dbo].[tblOverNightPermissions] ([OverNightID]) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT [FK_tblOverNightToVehicles_1] FOREIGN KEY ([VehicleID]) REFERENCES [dbo].[tblVehicles] ([VehicleID]) ON DELETE CASCADE ON UPDATE CASCADE
);
What I want to do is select record from tblOverNightPermissions and group them by month. I also want to count the number of records for that month and grouped by the vehicle ID which is in tblOverNightToVehicles. The goal is to run a check to make sure there have not been more than 5 overnightpermissions per vehicle id per month. It gets kind of tricky because the database design is not sound. As you can see, the NoOfDays field in the tblOvernightPermissions makes things complicated. Instead of there always being a set number of records per month, users have the ability to select up to 5 consecutive days of parking. So if I park today and select 5 days my record entry will look like this
DateAndTime = 5/8/2014
Address = x
Direction = S
NoOfDays = 5
UserId = 1
OvernightId = 1
Exempt = 0
Beat = 2
That means, for the month I will only have one physical record in tblOverNightPermissions that represents 5 days of parking. I could just as easily create 5 records in the table to signify 5 days of parking and thats where the issue comes in. Writing conditionals in TSQL to take into account if a record has NoOfDays > 1 add that to the count of the physical records for the month.
Here are the scripts to populate your databases
Script to populate tblOvernightPermissions https://dl.dropboxusercontent.com/u/62170850/tblOvernightPermissions.txt
Script to populate tblOvernightToVehicles
https://dl.dropboxusercontent.com/u/62170850/tblOverNightToVehicles.txt
SELECT DATEADD(month, DATEDIFF(month, 0, p.DateAndTime), 0) AS [Month],
SUM(p.NoOfDays) As Days
FROM tblOverNightPermissions p
INNER JOIN tblOverNightToVehicles v ON p.OverNightID = v.OverNightID
GROUP BY DATEADD(month, DATEDIFF(month, 0, p.DateAndTime), 0), v.VehicleID
HAVING SUM(p.NoOfDays) >= 5