SQL- Write script to show project name and dates - sql

I'm new to SQl and just going through some exercises. I'm trying to do scripts but need some assistance and would appreciate if someone can help me with the below topic which I am stuck on.
Table structure
**Project**
ID(PK) NAME Due_Date
1 Alpha 1/1/2040
2 Bravo 3/1/2030
3 Charlie 2/1/2017
4 Delta 4/1/2017
*Employee*
ID(PK) NAME
1 Kevin
2 Mike
3 Eric
4 Ira
5 Peter
*Project Assignment*
ID(PK) ProjectID(FK) EmployeeID(FK)
1 1 1
2 1 2
3 2 2
4 2 3
5 3 3
6 3 4
7 1 3
Question
Write a script that will return all project names and how much time (in days) is left until they are due for all projects which have not been completed yet.

If your question is asked correctly, then you only need the projects table. But I doubt that is what you want.
SELECT Name,
DATEDIFF (DAY, GETDATE(), Due_Date) AS DaysRemaining
FROM Project
WHERE Due_Date > GETDATE()
If you need employee data included, please adjust your question.

From my understanding i do this,
select pa.ID,e.NAME,p.NAME,p.Due_Date, DATEDIFF (DAY, GETDATE(), Due_Date) AS
DaysRemaining from
Project_Assignment pa inner join project p
on pa.projectid = p.id
inner join Employe e
on pa.EmployeeID = e.ID
and p.due_date > getdate()
Revert me any clarifications needed...

Related

SQL for joining two tables and grouping by shared column

I want to join two tables and use the column they both share to group the results, including a null result for those accountIds which only appear in one table.
Table a
AccountId
productApurchases
Steve
1
Jane
5
Bill
10
Abed
2
Table b
AccountId
productApurchases
Allan
1
Jane
10
Bill
2
Abed
1
Mike
2
Desired output
AccountId
productApurchases
productBpurchases
Steve
1
0
Jane
5
10
Bill
10
2
Abed
2
1
Mike
0
2
I've been trying with various joins but cannot figure out how to group by all the account ids.
Any advice much appreciated, thanks.
Use full join:
select accountid,
coalesce(productApurchases, 0) as productApurchases,
coalesce(productBpurchases, 0) as productBpurchases
from a full join
b
using (accountid);

SQL Query: Join (or select) 2 columns from 1 table with 1 column from another table for a view without extra join columns

This is my very first Stackoverflow post, so I apologize if I am not formatting my question correctly. I'm pounding my head against the wall with what I'm sure is a simple problem. I have a table with a bunch of event information, about 10 columns as so:
Table: event_info
date location_id lead_user_id colead_user_id attendees start end <and a few more...>
------------------------------------------------------------------------------------------------
2020-10-10 1 3 1 26 2100 2200 .
2020-10-11 3 2 4 18 0600 0700
2020-10-12 2 5 6 6 0800 0900
And another table with user information:
Table: users
user_id user_name display_name email phone city
----------------------------------------------------------------------
1 Joe S goofball ...
2 John T schmoofball ...
3 Jack U aloofball ...
4 Jim V poofball ...
5 Joy W tootball ...
6 George A boring ...
I want to create a view that has only a subset of the information, not full table joins. The event table lead_user_id and colead_user_id columns both refer to the user_id column in the users table.
I want to create a view like this:
date Location Lead Name CoLead Name attendees
---------------------------------------------------------------------
2020-10-10 1 Jack U Joe S 26
2020-10-11 3 John T Jim V 18
2020-10-12 2 Joy W George A 6
I have tried the following and several iterations like it to no avail...
SELECT
E.date, E.location,
U1.display_name AS Lead Name,
U2.display_name AS CoLead Name.
E.attendees
FROM
users U1, event_info E
INNER JOIN
event_info E ON U1.user_id = E.lead_user_id
INNER JOIN
users U2 ON U2.user_id = E.colead_user_id
And I get the dreaded
You have an error in your SQL Syntax
message. I'm not surprised, as I've really only ever used joins on single columns or nested select statements... this two columns pointing to one is throwing me for a loop. Help!
correct query for this matter
SELECT
E.date, E.location,
U1.display_name AS Lead Name,
(select display_name from users where user_id=E.colead_user_id) AS CoLead Name,
E.attendees
FROM
event_info E
INNER JOIN
users U1 ON U1.user_id = E.lead_user_id

Solving Logical Questions Using SQL

I am trying to solve a problem for a fun work exercise showing that SQL can be used to solve it. It is a puzzle that goes as follows:
Successfully navigating the waters during sea voyages is a challenging task. A captain’s most important decision is selecting the right crew for the voyage. A mix of different skill sets are required to sail the ship efficiently, navigate to the destination, and fish for food along the way.
Table 1 shows a list of crew members that are available for you to hire for the voyage. Each crew member demands a salary for the voyage and has different skill levels of Fishing, Sailing, and Navigation.
In order for your journey to be successful, you must have a cumulative skill of 15 or more in each of the three skill categories from all of your chosen crew members. You may choose as many crew members as you like.
Question: What is the minimum achievable cost for the voyage?"
I would say I am what I would consider an intermediate to advanced (depending on the situation) SQL user.
Not asking for an answer per-say but I have thought about the best way to solve and I was first thinking using a WHILE loop in some way. I have create a table to hold the data and added a 'salary_ranking' column (below). I am curious if anyone has any tips or suggestions on routes to go? I would like to use something I have never used before but also am trying to get to the most efficient answer.
Here is the data (I added the last column):
NAME FISHING SAILING NAVIGATION SALARY SALARY_RANK
---------- ----------- ----------- ----------- ----------- -----------
Amy 3 5 1 46000 3
Bill 1 2 5 43000 2
Carl 3 4 2 47000 4
Dan 4 3 1 36000 1
Eva 4 2 2 43000 2
Fred 1 3 4 55000 5
Greg 3 1 5 68000 8
Henry 5 4 2 64000 7
Ida 3 3 3 60000 6
(9 rows affected)
This is a CTE version, where I first create test data, then run a recursive query, using a MaxID to prevent it doing all the permutations.
declare #t table(Id int, NAME varchar(10), FISHING int, SAILING int, NAVIGATION int, SALARY int)
insert #t values (1,'Amy',3,5,1,46000)
,(2,'Bill',1,2,5,43000 )
,(3,'Carl',3,4,2,47000)
,(4,'Dan',4,3,1,36000)
,(5,'Eva',4,2,2,43000)
,(6,'Fred',1,3,4,55000)
,(7,'Greg',3,1,5,68000)
,(8,'Henry',5,4,2,64000)
,(9,'Ida',3,3,3,60000 )
;with cte as (
select convert(varchar(1000),name) as crew, fishing, sailing, navigation, salary, ID as MaxID from #t
union all
select convert(varchar(1000),cte.crew+', '+ t.name), cte.fishing+t.fishing, cte.sailing+t.sailing, cte.navigation+t.navigation, cte.salary+t.salary, t.ID
from #t t
join cte on t.ID>cte.MaxID
)
select top 1 crew,fishing,sailing,navigation,salary
from cte
where fishing>=15 and sailing>=15 and navigation>=15
order by salary
result is:
crew fishing sailing navigation salary
Amy, Bill, Carl, Greg, Henry 15 16 15 268000

Report on a point in time

I am about to create what I assume will be 2 new tables in SQL. The idea is for one to be the "live" data and a second which would hold all the changes. Dates are in DD/MM/YYYY format.
Active
ID | Name | State Date | End Date
1 Zac 1/1/2016 -
2 John 1/5/2016 -
3 Sam 1/6/2016 -
4 Joel 1/7/2016 -
Changes
CID | UID | Name | Start Date | End Date
1 1 Zac 1/1/2016 -
2 4 Joel 1/1/2016 -
3 4 Joel - 1/4/2016
4 2 John 1/5/2016 -
5 3 Sam 1/6/2016 -
6 4 Joel 1/7/2016 -
In the above situation you can see that Joel worked from the 1/1/2016 until the 1/4/2016, took 3 months off and then worked from the 1/7/2016.
I need to build a query where by I can pick a date in time and report on who was working at that time. The above table only lists the name but there will be many more columns to report on for a point in time.
What would be best way to structure the tables to be able to achieve this query.
I started writing this last night and finally coming back to it. Basically you would have to use your change table to create a Slowly Changing Dimension and then generate a row number to match your start and ends. This will assume however that your DB will never be out of sync by adding 2 start records or 2 end records in a row.
This also assumes you are using a RDBMS that supports common table expressions and Window Functions such as SQL Server, Oracle, PostgreSQL, DB2....
WITH cte AS (
SELECT
*
,ROW_NUMBER() OVER (PARTITION BY UID ORDER BY ISNULL(StartDate,EndDate)) As RowNum
FROM
Changes c
)
SELECT
s.UID
,s.Name
,s.StartDate
,COALESCE(e.EndDate,GETDATE()) as EndDate
FROM
cte s
LEFT JOIN cte e
ON s.UID = e.UID
AND s.RowNum + 1 = e.RowNum
WHERE
s.StartDate IS NOT NULL
AND '2016-05-05' BETWEEN s.StartDate AND COALESCE(e.EndDate,GETDATE())

Get latest date before date value in row

I am using MSSQL 2008 R2. I am attempting to get the latest data date up to a date stored in another column. I am able to pull the latest data date overall using max(ProcedureDate) in a subquery; however, i need the latest date before the date that's stored in the column.
Here's an example:
Current Table: Procedures
ID Patient ProcedureType ProcedureDate
1 George ExamA 1/1/2013
2 George TreatmentA 1/3/2013
2 George TreatmentB 1/5/2003
4 George ExamB 2/1/2013
5 George TreatmentA 2/5/2013
Desired Table: ProceduresWithLastExam
ID Patient ProcedureType ProcedureDate LastExamDate DaysSinceLastExam LastExamType
1 George ExamA 1/1/2013 1/1/2013 0 ExamA
2 George TreatmentA 1/3/2013 1/1/2013 2 ExamA
3 George TreatmentB 1/5/2013 1/1/2013 4 ExamA
4 George ExamB 2/1/2013 2/1/2013 0 ExamB
5 George TreatmentA 2/5/2013 2/1/2013 4 ExamB
I have attempted using the following, but it only pulls back the latest data date for that Patient.
select p.*, a.LastExamDate, a.ProcedureType as LastExamType from Procedures p
left join (
select exams.Patient, exams.ProcedureType, MAX(exams.ProcedureDate) as LastExamDate from Procedures exams
where ProcedureType like 'Exam%'
group by exams.Patient, exams.ProcedureType
)a
on p.Patient = a.Patient
The results for all rows is 2/1/13 as LastExamDate and ExamB as LastExamType.
I have attempted including some additional date parameters in my left join, in my where clause, and in my subquery to no success.
Please note I have omitted datediff logic until I can get the correct dates to return.
Thanks in advance for the help.
You can use OUTER APPLY. It is like a correlated subquery but allows multiple columns:
SELECT p.ID,
p.Patient,
p.ProcedureType,
p.ProcedureDate,
[LastExamDate] = exam.ProcedureDate,
[DaysSinceLastExam] = DATEDIFF(DAY, exam.ProcedureDate, p.ProcedureDate),
[LastExamType] = exam.ProcedureType
FROM Procedures p
OUTER APPLY
( SELECT TOP 1 exams.ProcedureType, exams.ProcedureDate
FROM Procedures exams
WHERE Exams.ProcedureType LIKE '%Exam%'
AND Exams.Patient = p.Patient
AND Exams.ProcedureDate <= p.ProcedureDate
ORDER BY Exams.ProcedureDate DESC
) exam;
Example On SQL Fiddle
This can be done with OUTER APPLY:
SELECT A.*,
B.ProcedureDate LastExamDate,
DATEDIFF(DAY,B.ProcedureDate,A.ProcedureDate) DaysSinceLastExam,
B.ProcedureType
FROM Procedures A
OUTER APPLY ( SELECT TOP 1 *
FROM Procedures
WHERE Patient = A.Patient
AND ProcedureDate <= A.ProcedureDate
AND ProcedureType LIKE 'Exam%'
ORDER BY ProcedureDate DESC) B
Here is a demo for you to try.