Complex T-SQL Statement - sql

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

Related

In a SELECT command, how do I use data from one table to specify data in another?

I have 2 tables. What is important is the PlayerId and the Username.
CREATE TABLE [dbo].[Run]
(
[RunId] INT NOT NULL,
[PlayerId] INT NOT NULL,
[Duration] TIME(7) NOT NULL,
[DateUploaded] NCHAR(10) NOT NULL,
[VersionId] INT NOT NULL,
PRIMARY KEY CLUSTERED ([RunId] ASC),
CONSTRAINT [FK_Run_Player]
FOREIGN KEY ([PlayerId]) REFERENCES [dbo].[Player] ([PlayerId]),
CONSTRAINT [FK_Run_Version]
FOREIGN KEY ([VersionId]) REFERENCES [dbo].[Version] ([VersionId])
);
CREATE TABLE [dbo].[Player]
(
[PlayerId] INT NOT NULL,
[Username] NCHAR(20) NOT NULL,
[ProfilePicture] IMAGE NULL,
[Country] NCHAR(20) NOT NULL,
[LeagueId] INT NULL,
[DateJoined] DATE NULL,
PRIMARY KEY CLUSTERED ([PlayerId] ASC),
CONSTRAINT [FK_Player_League]
FOREIGN KEY ([LeagueId]) REFERENCES [dbo].[League] ([LeagueId])
);
I have a select command:
SELECT
PlayerId, Duration, VersionId, DateUploaded
FROM
[Run]
(with apologies in advance for my messy made up pseudocode), what I need it to do is:
SELECT (Player.PlayerId.Username)
What I basically need it to do, is instead of giving me just PlayerId, I need it to get the corresponding Username (from the other table) that matches each PlayerId (PlayerId is a foreign key)
So say for example instead of returning
1, 2, 3, 4, 5
it should return
John12, Abby2003, amy_932, asha7494, luke_ww
assuming, for example, Abby2003's PlayerId was 2.
I've done trial and error and either nobody's tried this before or I'm searching the wrong keywords. This is using VS 2022, ASP.NET Web Forms, and Visual Basic, but that shouldn't affect anything I don't think. Any syntax ideas or help would be greatly appreciated.
try this for join the 2 Table togother
SELECT R.RunId
,R.PlayerId
,R.Duration
,R.DateUploaded
,R.VersionId
,P.Username
,P.ProfilePicture
,P.Country
,P.LeagueId
,P.DateJoined
FROM Run R
inner join Player P on R.PlayerId = P.PlayerId
Usually in this case joins are used. You can join the two tables together, give them aliases (or don't, personal preference really), then select what you need. In this case, you would probably want an inner join. Your query would probably look something like this:
SELECT p.Username FROM [Run] r
INNER JOIN [Player] p ON r.PlayerId = p.PlayerId
Then if you need to you can put a WHERE clause after that.
More about joins here

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?

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.

Using sql function on CHECK constraint for newly inserted row

First of all i need help with this for my bachelor thesis. I'm doing the whole database on sql server 2008 Release 2.
The problem is with check constraint that is using a function that is working on her own but not with the use in the constraint. The result of the constraint should be something like this: An employee could go only on one bussines trip per day.
Table Bussines trips:
CREATE TABLE SluzebniCesta(
idSluzCesty int PRIMARY KEY NOT NULL,
DatumCesty DATE NOT NULL,
CasOdjezdu TIME(0) NOT NULL,
CasPrijezdu TIME(0),
CONSTRAINT Odjezd_prijezd CHECK(CasPrijezdu > DATEADD(hour,2,CasOdjezdu))
);
Table that contains the employs that goes on bussines trip:
CREATE TABLE ZamNaCeste(
idZamNaCeste int PRIMARY KEY NOT NULL,
SluzebCestaID int NOT NULL,
ZamestnanecID int NOT NULL,
FOREIGN KEY (ZamestnanecID) REFERENCES Zamestnanec(idZamestnance),
FOREIGN KEY (SluzebCestaID) REFERENCES SluzebniCesta(idSluzCesty)
);
Foreign key ZamestnanecID is an employee's id and SluzebCestaID is the bussines trip id.
Now the function :
CREATE FUNCTION myCheckZamNaCeste(#SluzebCestaID int, #ZamestnanecID int)
RETURNS int
AS
BEGIN
DECLARE #retVal int;
DECLARE #Zamestnanec int;
DECLARE #SluzebniCesta int;
SET #Zamestnanec = (SELECT idZamestnance FROM Zamestnanec WHERE idZamestnance=#ZamestnanecID);
SET #SluzebniCesta = (SELECT idSluzCesty FROM SluzebniCesta WHERE idSluzCesty=#SluzebCestaID);
IF EXISTS ( SELECT DatumCesty FROM SluzebniCesta
WHERE idSluzCesty = #SluzebniCesta
AND DatumCesty IN (SELECT DatumCesty FROM ZamNaCeste
LEFT JOIN SluzebniCesta
ON ZamNaCeste.SluzebCestaID = SluzebniCesta.idSluzCesty
WHERE ZamestnanecID=#Zamestnanec))
BEGIN
SET #retVal=0;
END
ELSE
BEGIN
SET #retVal=1;
END
return #retVal
END
GO
And the alter table for the table that contains evidence of employee and their bussines trips:
ALTER TABLE ZamNaCeste
ADD CONSTRAINT check_cesty_zamestnance CHECK(dbo.myCheckZamNaCeste(SluzebCestaID,ZamestnanecID)=1);
And when I try to enter any new row the constraint is broken even if the function gives the right data. return 1 is the good result ....
In the first place, I'm not sure but it looks like the two set statements in the function are going out to retrieve from tables exactly the same values they already have from being passed in as parameters.
In the second place, I don't see anything limiting trips in the same day. Anywhere.
If you wanted to limit a trip by an employee to one per day, that is easy.
CREATE TABLE ZamNaCeste(
idZamNaCeste int PRIMARY KEY NOT NULL,
SluzebCestaID int NOT NULL,
ZamestnanecID int NOT NULL,
TripDate date not null,
FOREIGN KEY (ZamestnanecID) REFERENCES Zamestnanec(idZamestnance),
FOREIGN KEY (SluzebCestaID) REFERENCES SluzebniCesta(idSluzCesty),
constraint UQ_OneTripPerDay unique( ZamestnanecID, TripDate )
);
The unique constraint ensures the same employee cannot log more than one trip on the same day.
Well in the end i solved with a more sophisticated and better looking solution. The employ is limited with the times of arrival and departure. And i solved it with a function that returns number of incorrect occurences, if its zero than its all right and it works:
SELECT COUNT(*) FROM(SELECT * FROM SluzebniCesta JOIN ZamNaCeste
ON SluzebniCesta.idSluzCesty = ZamNaCeste.SluzebCestaID) AS a
JOIN (SELECT * FROM SluzebniCesta2 JOIN ZamNaCeste
ON SluzebniCesta.idSluzCesty = ZamNaCeste.SluzebCestaID)AS b
ON a.SluzebCestaID b.SluzebCestaID
AND a.CasOdjezdu b.CasOdjezdu
AND a.ZamestnanecID = b.ZamestnanecID
AND (SELECT SluzebniCesta.DatumCesty FROM SluzebniCesta
WHERE SluzebniCesta.idSluzCesty = a.SluzebCestaID) = (SELECT SluzebniCesta.DatumCesty
FROM SluzebniCesta WHERE SluzebniCesta.idSluzCesty = b.SluzebCestaID)

SQL constraint for limiting a daily task

I am teaching myself SQL and I am stuck. I have a Car-garage database with a table called Tasks. The table Tasks has 3 columns: Tasknumber(PK), NumberPlate, and DaySchedule. In the DDL I want to use a constraint which checks the number of plates and allows only one task a day.
The below is what I have tried. However, it restricts per record instead of per number of plates.
CREATE TABLE Tasks (
Tasknumber NUMERIC(5) not null,
NumberPlate VARCHAR(8) not null,
DaySchedule DATE not null,
Description VARCHAR(255) null,
CONSTRAINT PK_Tasknumber PRIMARY KEY (Tasknumber),
D AS DAY(DaySchedule) PERSISTED,
M AS MONTH(DaySchedule) PERSISTED,
Y AS YEAR(DaySchedule) PERSISTED,
CONSTRAINT UQ_DATA_DMY UNIQUE(D,M,Y)
)
What can I do to correct this?
If I understand correctly, you only need a UNIQUE constraint on (NumberPlate, DaySchedule). Then, for every NumberPlate, there will be at most one Task per Day.