Syntax for CHECKing inserted value against another table's - sql

I'm adding a table in my Database:
***Enrollments***
CourseID
Student ID
EnrollmentDateTime
I already have a table:
***Courses***
CourseID
StartDate
When someone's inserted data into the Enrollments table, I want to check whether the enrollment date is lesser than/ before the start date; I know what needs to be done, but am lacking the syntax on how to do so. So far, I have the following, but am at a loss on how to proceed.
Create Table Enrollments(
StudentID int NOT NULL Foreign Key REFERENCES dbo.Students(StudentID),
CourseID int NOT NULL Foreign Key REFERENCES dbo.Courses(CourseID),
EnrollmentDateTime Datetime NOT NULL CHECK (dbo.fCheckDate(EnrollmentDateTime, CourseID) = 1))
...
create function dbo.fCheckDate (#StartDate Datetime, #CourseID int)
Returns bit
AS
Begin
Return(SELECT E.StartDate
FROM dbo.Enrollments E
WHERE #CourseID = E.CourseID
End
go

Such function-based checks are quite expensive. But, you need a function to return the course date:
create function dbo.getStartDate (#CourseID int)
Returns datetime
AS
Begin
Return (SELECT c.StartDate
FROM dbo.Courses c
WHERE c.CourseID = #CourseID
);
End;
Create Table Enrollments (
StudentID int NOT NULL Foreign Key REFERENCES dbo.Students(StudentID),
CourseID int NOT NULL Foreign Key REFERENCES dbo.Courses(CourseID),
EnrollmentDateTime Datetime NOT NULL CHECK (EnrollmentDateTime < getStartDate(CourseID))
);

Related

my function returns null results and I'm not sure what is wrong (MySQL)

My function to find the cheapest property with n bedrooms is always returning null. I'm not sure what the issue is right now.
DELIMITER $$
DROP FUNCTION IF EXISTS cheapest_property_with_n_bedrooms;
CREATE FUNCTION cheapest_property_with_n_bedrooms (numBedrooms INT)
RETURNS INT DETERMINISTIC
BEGIN
DECLARE PropertyID INT;
DECLARE bedrooms INT;
SET PropertyID = (SELECT Property.property_id
FROM Property
JOIN Listing ON Listing.property_FK = Property.property_id
JOIN Amenities ON Amenities.property_FK = Property.property_id
GROUP BY Amenities.num_bedrooms
HAVING Amenities.num_bedrooms = numBedrooms
);
RETURN PropertyID;
END$$
DELIMITER ;
CREATE TABLE IF NOT EXISTS Amenities (
amenities_id INT PRIMARY KEY AUTO_INCREMENT,
property_FK INT,
num_bedrooms INT,
num_bathrooms INT,
num_garage INT,
num_kitchen INT,
num_parking INT,
CONSTRAINT FK_AMENITIES_PROPERTY FOREIGN KEY (property_FK) REFERENCES Property(property_id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS Property (
property_id INT PRIMARY KEY AUTO_INCREMENT,
property_name VARCHAR(50),
address_FK INT,
CONSTRAINT FK_PROPERTY_ADDRESS FOREIGN KEY (address_FK) REFERENCES Address(address_id) ON DELETE CASCADE ON UPDATE CASCADE
);
My query to call the function is this, where you can replace it with any number of bedrooms desired.
SELECT cheapest_property_with_n_bedrooms (1);

trigger for not inserting members doesnt work

I have this table
CREATE TABLE members
(
member_id INT PRIMARY KEY NOT NULL,
first_name VARCHAR(20),
last_name VARCHAR(20),
web_page VARCHAR(200),
e_mail VARCHAR(200),
cv VARCHAR(800),
dep_id INT,
teacher_id INT
);
and I want to create a trigger that if someone wants to insert a member which has a dep_id of 1 or 2 or 3.
And the teacher_id is different than NULL (as the teacher_id column is filled with either NULL or an id of another member)
I came up with this
CREATE TRIGGER employee_insup1
ON members
FOR INSERT, UPDATE
AS
DECLARE #dep_id INT, #teacher_id INT
SELECT #dep_id = i.dep_id, #teacher_id = i.teacher_id
FROM inserted i
IF ((#dep_id = 1) AND (#teacher_id != NULL))
BEGIN
RAISERROR('Teacher_id expects NULL',16,1)
ROLLBACK TRANSACTION
END
but after all if I try to insert a member with dep_id 1 and teacher_id 7(for example) it will be registered
You don't need a trigger for this. A check constraint is sufficient:
alter table members add constraint chk_members_dep_teacher
check (dep_id not in (1, 2, 3) or teacher_id is not null);
Specifically, this ensures that when dep_id is in one of those departments, then the teacher_id is not null. You might find the logic easier to follow as:
alter table members add constraint chk_members_dep_teacher
check (not (dep_id nt in (1, 2, 3) and teacher_id is null) );

Create SQL Function view with User ID and Date range

As I title says, I need to create a Function View of two tables.
Below are the SQL Tables
CREATE TABLE User_Specialist(
ID_User_Specialist INT NOT NULL,
Name_User_Specialist VARCHAR(50) NOT NULL,
CONSTRAINT PK_ID_User_Specialist PRIMARY KEY(ID_User_Specialist),
GO
CREATE TABLE Incident(
ID_Incident INT IDENTITY(1,1) NOT NULL,
Incident_Creation_Date DATETIME NULL,
Assigned_Specialist INT NULL,
CONSTRAINT FK_Assigned_Specialist FOREIGN KEY (Especialista_Asignado) REFERENCES Usuario_Especialista(ID_Usuario_Especialista),
GO
Based on the previous information, I need the function to display Assign Specialist and the dates that the Incident was created.
Right know this is what I got:
CREATE FUNCTION View_Date (#ID_User_Incident INT)
RETURNS INT
AS
BEGIN
DECLARE #Total_Incidents INT
SELECT #Total_Incidents = COUNT(ID_Incident)
FROM Incidents i, User_Specialist u
WHERE i.ID_Incident = u.ID_User_Specialist AND u.ID_User_Specialist =#ID_User_Incident
RETURN (#Total_Incidents)
END
GO
DECLARE #Specialist_ID int;
EXEC #Specialist_ID = [dbo].View_Date
#ID_Incidentes_Usuarios = 5;
SELECT #Specialist_ID AS 'Assigned Specialist Incidents'
GO
The only thing missing is the dates range.
I believe you changed your table and field names to English from Spanish. You have missed some of them and there were some missing parenthesis. As much as I understand I changed them to understand better.
CREATE TABLE User_Specialist
(
ID_User_Specialist INT NOT NULL,
Name_User_Specialist VARCHAR(50) NOT NULL
CONSTRAINT PK_ID_User_Specialist PRIMARY KEY(ID_User_Specialist)
)
GO
CREATE TABLE Incident
(
ID_Incident INT IDENTITY(1,1) NOT NULL,
Incident_Creation_Date DATETIME NULL,
Assigned_Specialist INT NULL
CONSTRAINT FK_Assigned_Specialist FOREIGN KEY (Assigned_Specialist) REFERENCES User_Specialist(ID_User_Specialist)
)
GO
If you want to see multiple columns or rows as result you need to use Table-valued Function. I have created sample query from your table and prepared function. you can change it with what you want.
CREATE FUNCTION dbo.FN_ViewDate
(
#ID_User_Incident INT
)
RETURNS #Result TABLE
(
TotalIncidents INT
,FirstIncidentDate DATETIME
,LastIncidentDate DATETIME
)
AS
BEGIN
INSERT INTO #Result
SELECT COUNT(ID_Incident)
,MIN(Incident_Creation_Date)
,MAX(Incident_Creation_Date)
FROM Incident I
LEFT JOIN User_Specialist U ON I.Assigned_Specialist = U.ID_User_Specialist
WHERE I.Assigned_Specialist = #ID_User_Incident
RETURN
END
GO
I think this query can help you.
declare #count int = 0 , #dates varchar(200) =''
SELECT #count+=1 , #dates +=' '+ i.Incident_Creation_Date
FROM Incidents i, User_Specialist u
WHERE i.ID_Incident = u.ID_User_Specialist AND u.ID_User_Specialist =#ID_User_Incident
select #count as [count] ,#dates [incidentDates]

SQL How to convert this to a SubQuery?

Learning, be kind.
I am trying to understand how this works and I have done several successful conversions, but this one I am stumped on.
How do I take this code and convert it to a subquery? I'm a little lost.
SELECT o.FirstName + ' ' + o.LastName AS Driver, COUNT(DISTINCT s.vehicleID) NoOfBusesUsed
FROM Operators AS o, Runs AS r, Schedules AS s JOIN Trips AS t
ON s.scheduleID = t.scheduleID
WHERE r.BidDate BETWEEN '09/01/2004' AND '09/30/2004'
GROUP BY o.FirstName + ' ' + o.LastName
HAVING COUNT(s.vehicleID) > 1
Here is how my tables are setup. If more info is needed, I can post.
CREATE TABLE Operators
(
SeniorityNumber char(4) NOT NULL
CONSTRAINT ck_Operators_Seniority
CHECK (SeniorityNumber LIKE '[0-9][0-9][0-9][0-9]'),
FirstName varchar(25) NOT NULL,
LastName varchar(35) NOT NULL,
HireDate smalldatetime
CONSTRAINT ck_Operators_HireDate CHECK (HireDate <=Getdate())
)
CREATE TABLE Trips
(
RouteNumber varchar(4) NOT NULL,
StartLocation varchar(50) NOT NULL,
StartTime time NOT NULL,
EndLocation varchar(50) NOT NULL,
EndTime time NOT NULL,
EffectiveDate smalldatetime NOT NULL
CHECK (EffectiveDate >= cast('1/1/2000' as smalldatetime)),
CONSTRAINT ck_Trips_StartEnd CHECK (EndTime > StartTime)
)
CREATE TABLE Vehicles
(
Manufacturer varchar(50)
DEFAULT 'Gillig',
Model varchar(50),
ModelYear int
DEFAULT DatePart(yyyy,GetDate())
CHECK (ModelYear <= DatePart(yyyy,GetDate())),
PurchaseDate smalldatetime
)
GO
ALTER TABLE operators
ADD OperatorID int IDENTITY --Primary Key
GO
ALTER TABLE Operators
ADD CONSTRAINT pkOperators Primary key (OperatorID)
ALTER TABLE Vehicles
ADD VehicleID int IDENTITY Primary Key
ALTER TABLE Trips
ADD TripID int IDENTITY Primary key
GO
CREATE TABLE Runs
(
RunID int IDENTITY NOT NULL Primary Key,
OperatorID int NOT NULL REFERENCES Operators,
BidDate date NOT NULL
CONSTRAINT ckRunBidDate CHECK
(biddate <= dateadd(mm,6,getdate())) --getdate() + 180
)
GO
CREATE TABLE Schedules
(
ScheduleID int IDENTITY Primary Key,
RunID int NOT NULL,
VehicleID int NOT NULL,
CONSTRAINT fk_Schedules_Runs FOREIGN KEY (RunID)
REFERENCES Runs(RunID),
CONSTRAINT fk_Schedules_Vehicles FOREIGN KEY (VehicleID)
REFERENCES Vehicles
)
ALTER TABLE Trips
ADD ScheduleID int NULL REFERENCES Schedules
When you want to use a query as a sub-query you can use WITH statement or a derived table like:
With:
;WITH subQuery AS (
/* Your query here */
)
SELECT *
FROM subQuery
Derived table
SELECT *
FROM (
/* your query here */
) As subQuery
I think you should use a query like this:
SELECT
o.FirstName + ' ' + o.LastName AS Driver,
DT.cnt AS NoOfBusesUsed
FROM
Operators AS o
JOIN
(SELECT
r.OperatorID,
COUNT(DISTINCT s.VehicleID) AS cnt
FROM
Schedules s
JOIN
Runs r ON s.RunID = r.RunID
) AS DT
ON DT.OperatorID = o.OperatorID
WHERE
ISNULL(DT.cnt, 0) > 1

Adding CHECK constraint conflicts with IS NULL

I got a problem when I try to add a constraint to one of my tables. I want to check in a function so that a state is true and then returns 1 or 0 depending on if it is true. But in the function I check if a value in a column is NULL and that causes the error
The ALTER TABLE statement conflicted with the CHECK constraint "chk_StateFinished". The conflict occurred in database "databaseName", table "dbo.Participation".
the Function looks like this
CREATE FUNCTION CheckStateFinished(#StudentID varchar(10), #CourseID varchar(10), #CoursePeriod varchar(10),
#SchoolYear int, #State varchar(15)) RETURNS int
AS BEGIN
DECLARE #Grade varchar(1)
SELECT #Grade = Grade FROM Participation WHERE StudentID = #StudentID AND CourseID = #CourseID AND CoursePeriod = #CoursePeriod AND SchoolYear = #SchoolYear
RETURN CASE WHEN #State = 'Avslutad' AND #Grade = 'U' OR #Grade IS NULL THEN 0
ELSE 1
END
END
And the Add Check Constraint looks like this:
ALTER TABLE Participation ADD CONSTRAINT chk_StateFinished CHECK (dbo.CheckStateFinished(StudentID, CourseID, CoursePeriod, SchoolYear, _State) = 1)
What should I do instead of IS NULL in the Function or should i do something else?
The issue is not in function CheckStateFinished but with existing data in table Participation on which CHECK CONSTRAINT is to be added. When we add Check constraint to an existing table using Alter table command by default it applies to both existing data and any new data.
There might be some row in table Participation where for given StudentID, CourseID, CoursePeriod, SchoolYear, _State parameters function is evaluating to 0 and hence Check constraint is getting failed.
In such a case use WITH NOCHECK option so that Check constraint applies only to new data.
create table Participation (Grade varchar(1),StudentID varchar(10), CourseID varchar(10), CoursePeriod varchar(10), SchoolYear int, [State] varchar(15))
insert into Participation values ('A','Student1','Course1','CourseP1',2013,'Avslutad')
-- for this row check constraint will work fine.
insert into Participation values ('U','Student2','Course1','CourseP1',2013,'Avslutad') -- for this row check constraint will fail.
insert into Participation values (NULL,'Student3','Course1','CourseP1',2013,'Avslutad')
-- for this row check constraint will fail.
insert into Participation values ('U','Student4','Course1','CourseP1',2013,'XYZ')
-- for this row check constraint will work fine.
--insert into Participation values ('A','Student5','Course1','CourseP1',2013,'XYZ')
Go
CREATE FUNCTION CheckStateFinished(#StudentID varchar(10), #CourseID varchar(10), #CoursePeriod varchar(10),
#SchoolYear int, #State varchar(15)) RETURNS int
AS BEGIN
DECLARE #Grade varchar(1)
SELECT #Grade = Grade FROM Participation WHERE StudentID = #StudentID AND CourseID = #CourseID AND CoursePeriod = #CoursePeriod AND SchoolYear = #SchoolYear
RETURN CASE WHEN #State = 'Avslutad' AND #Grade = 'U' OR #Grade IS NULL THEN 0
ELSE 1
END
END
Go
ALTER TABLE Participation WITH NOCHECK -- add this and your constraint will work.
ADD CONSTRAINT chk_StateFinished CHECK (dbo.CheckStateFinished('Student3','Course1','CourseP1',2013,'Avslutad') = 1)
Go