Find missing dates from multi table query - sql

I'm looking to write a query that can count missing entries from a table of dates based on skills that a resource has to forecast availability of resource for booking. I'm not sure if it can be done and I'm certainly struggling with the logic!!
Tables
Dates
ID dateFrom StaffID
1 01-06-2014 1
2 02-06-2014 1
3 03-06-2014 1
4 04-06-2014 1
5 05-06-2014 1
6 01-06-2014 2
7 03-06-2014 2
8 04-06-2014 2
9 05-06-2014 2
10 06-06-2014 2
(Free dates on the 6th for staffID 1 and 2nd for staffID 2)
Staff
StaffID Name
1 John
2 Paul
Skills
ID StaffID SkillID
1 1 1
2 1 2
3 1 3
4 2 2
5 2 3
6 2 4
So I want to write a query that says in June, for each of the skills there is X no of days available to book. Is this even possible? looking for records that don't exist to join with a staff table?
I've put together a calendar table that can identify days without bookings but I'm struggling from there on to be honest.
Any help would be greatly appreciated!!
Steve
EDIT: DB is SQL 2005.
Expected output (if possible)
SkillID Number of days available
1 20
2 22
3 14
etc

create a calendar table with all possible dates (booked or not)
select count(distinct ad.calendarDate), s.SkillID
from all_dates ad
cross join skills s
where not exists (
select 1 from
dates where dateFrom = ad.calendarDate
and StaffID = s.StaffID
)
group by s.SkillID

If I understand your problem, your query will be some thing like:
Select sum(temp.nbrDate), temp.SkillID from
(Select s.SkillID, count (d.ID) as nbrDate from Skills s, Dates d
where s.StaffID = d.StaffID
Group by SkillID) temp
group by SkillID
If you want to add a date range, add this in your where close:
and d.DateForm between '01-06-2014' and '30-06-2014'

Related

sql snowflake, aggregate over window or sth

I have a table below
days
balance
user_id
wanted column
2022/08/01
10
1
1
2022/08/02
11
1
1
2022/08/03
10
1
1
2022/08/03
0
2
1
2022/08/05
3
2
2
2022/08/06
3
2
2
2022/08/07
3
3
3
2022/08/08
0
2
3
since I'm new to SQL couldn't aggregate over window by clauses, correctly.
which means; I want to find unique users that have balance>0 per day.
thanks
update:
exact output wanted:
days
unque users
2022/08/01
1
2022/08/02
1
2022/08/03
1
2022/08/05
2
2022/08/06
2
2022/08/07
3
2022/08/08
3
update: how if I want to accumulate the number of unique users over time? with consideration of new users [means: counting users who didn't exist before], and the balance > 0
everyones help is appreaciated deeply :)
SELECT
*,
COUNT(DISTINCT CASE WHEN balance > 0 THEN USER_ID END) OVER (ORDER BY days)
FROM
your_table

How to add a condition to count function in PostgreSQL

I have these tables Course, subscription,subscription_Course(A table that creates a relation between Course and subscription), and another with Student. I want to Select all the id_courses that have a subscription count higher than 1 but only want to count the subscriptions from different students. Example: If a Student Subscribes two times the same course I want to have a condition that enables the count function to not count more than one time in these cases
These are my tables:
Student:
idStudent(pk)
cc
nif
1
30348507
232928185
2
30338507
231428185
3
30438507
233528185
4
30323231
3232132
Subscription
idsubscription(pk)
Student(fk)
value_subscription
vouchercurso
date
1
1
100
null
2021-11-01
2
2
150
null
2021-12-11
3
3
160
null
2021-01-03
4
4
500
null
1996-11-07
5
1
900
null
2001-07-05
6
2
432
null
2021-05-09
Subscription_Course
idsubscription(PK/fk)
id_Course(pk/fk)
Grade
1
3
9
2
4
15
3
5
12
6
3
9
5
4
16
2
6
20
6
5
4
For example, when counting within my table Subscription_Course only the id_course:5 would have a count higher than 1 because 3 and 4 have a subscription from the same student.
I have this query for now:
Select id_Course
From Subscription_Course
Group by id_Course
Having Count (id_Course)>1
I don't know what to do to add this condition to the count.
seems like you need to join to Subscription and count unique Student id's:
select id_Course
from Subscription_Course sc
join Subscription s
on s.idsubscription = sc.idsubscription
group by id_Course
having Count(distinct Studentid)>1
You can join the Subscription_Course table with the Subscription table in order to access the id_Student column. Then just count the distinct id_Student values for each id_Course value.
SELECT
Subscription_Course.id_Course,
COUNT(DISTINCT Subscription.id_Student) AS student_count
FROM Subscription_Course
INNER JOIN Subscription
ON Subscription_Course.id_Subscription = Subscription.id_Subscription
GROUP BY Subscription_Course.id_Course
HAVING COUNT(DISTINCT Subscription.id_Student) > 1
ORDER BY student_count DESC;
With result:
id_course | student_count
-----------+---------------
3 | 2
4 | 2
5 | 2

SQL Group By + Count with multiple tables

I'm studying for an interview next week which has a small data analysis component. The recruiter gave me the following sample SQL question which I'm having trouble wrapping my mind around a solution. I'm hoping that I'm not biting off more than I can chew ;)..
SAMPLE QUESTION:
You are given two tables:
AdClick Table (columns: ClickID, AdvertiserID, UserID, and other
fields) and AdConversion Table (columns: ClickID, UserID and other
fields).
You have to find the total conversion rate (# of conversions/# of
clicks) for users with 1 click, 2 click etc.
I've been playing with this for about an hour and keep hitting road blocks. I understand COUNT and GROUP BY but suspect I'm missing a simple SQL feature that I'm unaware of. This also makes it difficult for me to find any possible pointers/solutions via Google: not knowing the magic keywords to search on.
Example Input
dbo.AdConversion
----------------
ClickID UserID
1 1
2 1
4 1
5 3
6 2
7 2
12 1
9 4
10 4
dbo.AdClick
-----------
ClickID AdvertiserID UserID
1 1 1
2 2 1
3 1 2
4 1 1
5 1 3
6 2 2
7 3 2
8 1 1
9 4 4
10 2 4
11 3 4
12 2 1
Expected Result:
----------------
UserClickCount ConversionRate
4 80.00%
2 66.67%
1 100.00%
Explanation/Clarification:
Users with 4 AdConversion.ClickIDs (aka Conversions) have an 80% conversation rate.
Here there's just one user, UserID 1, which has 5 AdClicks with 4 AdConversions.
Users with 2 Conversions have a combined 6 Adclicks with 4 conversions for a conversion rate of 66.67%. Here, that'd be UserID 2 and 4.
Users with 1 Conversion, here only UserID 3, has 1 conversion against 1 AdClick for a 100% conversion rate.
Here's one possible solution I've come up with after some direction from Zack's comment. I can't imagine that it's the ideal solution or whether it has bugs in it or not:
DECLARE #Conversions TABLE
(
UserID int NOT NULL,
AdConversions int
)
INSERT INTO #Conversions (UserID, AdConversions)
SELECT adc.UserID, COUNT(adc.UserID)
FROM dbo.AdConversion adc
GROUP BY adc.UserID;
DECLARE #Clicks TABLE
(
UserID int NOT NULL,
AdClicks int
)
INSERT INTO #Clicks(UserID, AdClicks)
SELECT UserID, Count (ClickID)
FROM dbo.AdClick
GROUP BY UserID;
SELECT co.AdConversions, CONVERT(decimal(6,3), (CAST(SUM(co.AdConversions) AS float) / SUM(cl.AdClicks))) * 100
FROM #Conversions co
INNER JOIN #Clicks cl
ON co.UserID = cl.UserID
GROUP BY co.AdConversions;
Any advice would be greatly appreciated!
Thanks,
Michael
Your logic seems good. Here is a version with common table expressions and a little update with the numeric conversion:
WITH tConversions as
(SELECT UserID, COUNT(ClickID) as AdConversions
FROM AdConversion
GROUP BY UserID),
tClicks as
(SELECT UserID, COUNT(ClickID) as AdClicks
FROM AdClick
GROUP BY UserID)
SELECT co.AdConversions, CONVERT(decimal(10,2),CAST(SUM(co.AdConversions) as float) / SUM(cl.AdClicks) * 100) as ConversionRate
FROM tConversions co
INNER JOIN tClicks cl
ON co.UserID = cl.UserID
GROUP BY co.AdConversions
You can also use subqueries directly:
SELECT co.AdConversions, CONVERT(decimal(10,2),CAST(SUM(co.AdConversions) as float) / SUM(cl.AdClicks) * 100) as ConversionRate
FROM
(SELECT UserID, COUNT(ClickID) as AdConversions
FROM AdConversion
GROUP BY UserID)
as co
INNER JOIN
(SELECT UserID, COUNT(ClickID) as AdClicks
FROM AdClick
GROUP BY UserID)
as cl
ON co.UserID = cl.UserID
GROUP BY co.AdConversions

How do I add rows in one table in specific conditions?

I work on an Oracle database.
I have a table (it is a join table) but this is how it looks:
CustomerID days_attached Startdate enddate team
1 7 01-01-2016 08-01-2016 A
1 2 09-01-2016 10-01-2016 B
1 8 01-02-2016 09-02-2016 A
2 1 01-02-2017 02-02-2016 C
2 8 08-05-2017 16-05-2017 C
I need to know how long a person is attached to a specific team. A person can be attached to a person for a X amount of days. That person could be in a team. For instance in this case, how long is a person attached to team A = 7+8 15 days.
How do I get this in a SQL statement?
Our app only supports SQL not PL/sql .
I expect an output like:
CustomerID days_attached team
1 15 A
1 2 B
2 9 C
select customer, team, sum(dayattached) from table_name group by customer, team
hopefully this will help u

Cross Join for Missing table (Select all and Select or Insert the Missing Row Only)

I have two table and have to fill in a list of missing values in one of the table based on the other one. First table has student's information and the second table has Grade related info, Grade and Grade description.
Table One
ID Name yearWithUs Grade Course Level
1 Jim 2004 4 4
2 Jim 2004 4 1
2 Jim 2003 3 3
4 Jim 2002 2 3
4 Jim 2002 2 1
3 Jim 2001 1 2
3 Jim 2001 1 1
Table two -- logic is.. A Student in a higher Course Level can change to a lower Course Level at anytime during the semester. And It can only go downward 1 level at a time. Example: Jim in his second grade first was assigned to attend course in level 3. He need to attend course in level 2 first before he can attend course in level 1. Means. Row for course level 2 at jim's first grade is missing.
Table Two
ID Grade Grade_Desc Course Level Course Desc
1 1 First Grade 1 Basic
2 1 First Grade 2 Normal
3 1 First Grade 3 Hard
4 1 First Grade 4 Expert
5 2 Second Grade 1
6 2 Second Grade 2
7 2 Second Grade 3
8 2 Second Grade 4
. . .
. . .
. . .
Logic of Table Two
ID Grade Grade_Desc Course Level Possible Move
1 1 First Grade 1 Null
2 1 First Grade 2 1
3 1 First Grade 3 2
4 1 First Grade 4 3
Ouptput one ... how to use select statement to return Jim's Grade?
ID Name Grade_Desc Grade yerWithUs Course Level
1 Jim Fourth Grade 4 2004 4
2 Jim Fourth Grade 4 2004 3
3 Jim Fourth Grade 4 2004 2
4 Jim Fourth Grade 4 2004 1
5 Jim Third Grade 3 2003 3
6 Jim Second Grade 2 2002 3
7 Jim Second Grade 2 2002 2
8 Jim Second Grade 2 2002 1
9 Jim First Grade 2 2001 2
10 Jim First Grade 2 2001 1
Output Two..How to retrieve only the missing row into a new temp table?
ID Name Grade_Desc Grade yearWithUs Course Level
2 Jim Fourth Grade 4 2004 3
3 Jim Fourth Grade 4 2004 2
7 Jim Second Grade 2 2002 2
I am currently is using a messy Cursor Statement to do it. The structure looks really messy and hard to debug return errors. I did a lot of research, and saw people use Cross Join to fill the missing portion which looks really clean (See example below)... I have tried the script it myself in many different way by using the cross join example below...obviously, I failed. I found a similar question in stackoverflow..but I am not able to understand how does it work and why without looking at the data....I need help to understand how to use cross join to rerun missing row? and I am open to any other possible solution.
"SELECT calendar.Date,
Category.Cat,
Score = ISNULL(Scores.Score, 0)
FROM Calendar
CROSS JOIN Catogory
LEFT JOIN Scores
ON Scores.Cat = Category.Cat
AND Scores.Date = Calendar.Date
WHERE Calendar.DayOfMonth = 1;"
Inserting missing rows with a join
Thank You
This will produce that output:
select distinct name, grade, Grade_Desc
from one
cross join two
If select is all you want then:
Select row_number() over(order by (select 1)) as id, * from
(Select distinct name from t1)t1
cross join t2
Here is fiddle http://sqlfiddle.com/#!6/a8a42/3
Try this out:
Create #Temp
DECLARE #Name VARCHAR(100) = 'Jim'
SELECT ROW_NUMBER() OVER (ORDER BY B.Grade DESC,B.CourseLevel DESC) ID,
A.Name,
B.Grade_Desc,
B.Grade,
A.YearWithUs,
B.[Course Level]
INTO #temp
FROM
(
SELECT DISTINCT Name,YearWithUs,Grade
FROM TableOne
WHERE Name = #Name
) A
INNER JOIN TableTwo B
ON A.Grade = B.Grade
Output One
SELECT *
FROM #temp
Output Two into #OutputTwo(temp table)
SELECT A.* INTO #OutputTwo
FROM #temp A
LEFT JOIN TableOne B
ON A.Grade = B.Grade
AND A.[Course Level] = B.[Course Level]
WHERE A.Grade IS NULL AND A.[Course Level] IS NULL