I have a car rent management database and I created a query which should output car maintainer supervisors that have more than 1 subordinates (maintainers). In my case only one supervisor has 2 subordinates.
When I try to use this select statement, it still outputs all supervisors, when in reality I only need to output the first row. Would really appreciate your help, I am quite new in SQL and this is for my school project.
1 select s.name || ' ' || s.surname as "Supervisor", s.mobile_nr as "Telephone", count(w.id_worker) as "Total subworkers"
2 from supervisor s, worker w, maintainer m
3 where s.id_supervisor=w.id_supervisor and w.id_maintainer=m.id_maintainer and (select count(id_worker) from worker, maintainer where maintainer.id_maintainer=worker.id_maintainer)>1
4* group by s.name, s.surname, s.mobile_nr
SQL> /
Supervisor Telephone Total subworkers
------------------------------------------------------------- -------------------- ----------------
Marcis Janeks +37122176223 2
Ilona Katlina +37128632447 1
Skaidris Kalnins +37123389601 1
Zane Masta +37126874141 1
Karlis Maiznieks +37128610671 1
Modris Upmalis +37125012112 1
Ilgonis Smaidins +37129636642 1
Janis Kurpnieks +37126178482 1
Vladimir Kurcavenko +79061177915 1
Miraldas Hakomas +37022892633 1
10 rows selected.
Use a HAVING clause rather than an (uncorrelated) sub-query:
SELECT MAX(s.name || ' ' || s.surname) as "Supervisor",
MAX(s.mobile_nr) as "Telephone",
COUNT(w.id_worker) as "Total subworkers"
FROM supervisor s
INNER JOIN worker w
ON s.id_supervisor=w.id_supervisor
INNER JOIN maintainer m
ON w.id_maintainer=m.id_maintainer
GROUP BY s.id_supervisor
HAVING COUNT(w.id_worker) > 1
Note: you probably want to GROUP BY the primary key for the supervisor rather than using the name as there could be two people with the same name (and the same phone number if they shared an office).
Note 2: Use the ISO/ANSI standard join syntax rather than the legacy comma-join syntax from 30 years ago that is difficult to read.
Related
For my question I am to create a query showing the guest's full name that have made more than 2 bookings. It is to show the (family_name, given_name) in one column under the alias "Guest" AND alias "Count(*)" which what assume, counts the the guest_id from a2_booking (table1) which must be more than 2. The second table, "a2_guest", contains the guest_id (same as in a2_booking), family_name, given_name. What can I do to get the following query:
Guest COUNT(*)
-- ------------------------------------------------------------------------------------ ----------
-- Fellows, John 3
-- Gaye, Anthony 3
-- Grace, Thomas 3
-- Marvin, Leon 4
-- Oslovski, Boris 3
-- Rivers, Jill 3
-- Slater, Martin 3
-- Strettle, George
I only managed to use CONCAT to combine the family_name and given_name to one column on the first try and then I tried to count the guests that had multiple bookings made (but I didn't do the calculation greater than 2 yet).
Apologies all. I managed to find an answer that really helped.
SELECT x.family_name || ', ' || x.given_name AS "Guest", COUNT(y.guest) as
"COUNT(*)"
FROM a2_guest x JOIN a2_booking y
ON (x.guest_id = y.guest)
GROUP BY x.family_name || ', ' || x.given_name
HAVING COUNT(y.guest) > 2;
I appreciate the help though ;)
This question already has answers here:
Get top 1 row of each group
(19 answers)
Closed 10 months ago.
Let's say I had two tables that looked like this:
Prod_SerialNo
Prod_TestOnAt
Prod_AccountNo
SN0001
2021-04-08
045678
SN0001
2021-01-14
067891
SN0001
2021-11-29
091234
SN0002
2022-01-19
045678
SN0002
2020-07-30
045678
SN0002
2022-03-30
012345
SN0003
2022-04-01
078912
SN0003
2022-02-19
089123
SN0003
2022-03-18
023456
S_AccountNo
S_AccountType
S_AccountName
012345
Homeowner
Adam Smith
023456
Homeowner
Jeremy Chan
034567
Manufacturer
Anne Hudson
045678
Distributor
Barney Jones
056789
Distributor
Jasmine Coleman
067891
Homeowner
Christian Lewis
078912
Distributor
Heather Ogden
089123
Homeowner
Stephen Gray
091234
Distributor
Antony Newman
The Prod Table tabulates specific product tests by what serial number was used, when the product was tested, and who tested it. (There are other things in the table, including a primary key not shown here)
The S Table is a list of subscribers with a variety of information about them. S_AccountNo is the parent to Prod_AccountNo.
I want to query when the last test was performed for each Serial Number and what account name it was that performed the test, but I don't want multiple results (duplicates) for the same serial number. I have tried the following code:
SELECT
Prod_SerialNo,
MAX(Prod_TestOnAt) AS "Last Time Tested",
S_AccountName
FROM Prod
INNER JOIN S ON S.S_AccountNo = Prod.Prod_AccountNo
GROUP BY Prod_SerialNo, S_AccountName
ORDER BY Prod_SerialNo
However, the query ends up outputting the same serial number on multiple rows even though I ask for the max TestOnAt date and I group by serial number. What am I getting wrong?
I think there is no need to use Group by you can get result with Row_Number like this:
SELECT
t.Prod_SerialNo,
t.Prod_TestOnAt AS "Last Time Tested",
t.S_AccountName
FROM (
SELECT
Prod_SerialNo,
Prod_TestOnAt,
S_AccountName,
ROW_NUMBER() OVER (PARTITION BY Prod_SerialNo ORDER BY Prod_TestOnAt DESC) rw
FROM Prod
INNER JOIN S ON S.S_AccountNo = Prod.Prod_AccountNo
) t
WHERE t.rw=1
ORDER BY t.Prod_SerialNo
You are grouping by Prod_SerialNo, S_AccountName so you will get duplicate Prod_SerialNo if multiple rows exist with that Prod_SerialNo and different S_AccountNames. You could do a MAX on Prod_TestOnAt and get that value with it's Prod_SerialNo, then join the result on the table to get your desired info using a subquery like so:
SELECT
p.[Prod_SerialNo],
max.[LastTimeTested],
s.[S_AccountName]
FROM PROD as p
INNER JOIN
(
SELECT
Prod_SerialNo,
MAX(Prod_TestOnAt) as [LastTimeTested]
FROM Prod
GROUP BY [Prod_SerialNo]
) as max
on max.[Prod_SerialNo] = p.[Prod_SerialNo] and max.[LastTimeTested] = p.[Prod_TestOnAt]
INNER JOIN S as s
ON s.[S_AccountNo] = p.[Prod_AccountNo]
ORDER BY p.[Prod_SerialNo]
If you don't like the solution using ROW_NUMBER an alternative is to use CROSS APPLY to identify the last Prod_TestOnAt and the associated Prod_AccountNo.
SELECT DISTINCT p.Prod_SerialNo, ca.Prod_TestOnAt, s.S_AccountName
FROM Prod p
CROSS APPLY (SELECT TOP 1 Prod_TestOnAt, Prod_AccountNo
FROM Prod
WHERE Prod_SerialNo = p.Prod_SerialNo
ORDER BY Prod_TestOnAt DESC) ca
INNER JOIN S ON S.S_AccountNo = ca.Prod_AccountNo
This is my first month of being a Data Analyst, and I can't seem to find an answer that is specific enough to my problem here to help. I am having trouble getting this manager flag field to work and I think I'm getting confused by the joins.
The goal is to match the EMPLIDs of JOB_VW A to see if they exist in the Supervisor_ID column of Supervisor_VW K. Supervisor_VW K has ALL employees in the company (including supervisors) in the K.EMPLID column. Someone can be in both the supervisor ID column and EMPL column at the same time, but in different rows. The SUP ID is the EMPL ID of someone in a manager position.
For example:
Supervisor_VW K
EMPL ID EMPL NAME SUP ID SUP NAME
1 Smith, John 2 William, Mark
5 Jarvis, John 2 William, Mark
2 William, Mark 4 Rover, Spot
The results I am getting are as such
QUERY RESULTS
EMPLID EMPL NAME MANAGER FLAG
2 William, Mark Y
2 William, Mark Y
4 Rover, Spot Y
1 Smith, John N
5 Jarvis, John N
My current code is as follows:
SELECT CASE WHEN K.Supervisor_Id IS NULL THEN
'N'
ELSE
'Y'
END AS "ManagerFlag".....
FROM (SELECT K.*
FROM SUPERVISOR_VW K, JOB_VW A
WHERE K.SUPERVISOR_ID (+) = A.EMPLID
AND EXISTS (SELECT K1.EMPLID, K1.SUPERVISOR_ID
FROM SUPERVISOR_VW K1
WHERE K1.EMPLID IN K1.Supervisor_Id)
) K
So it seems that I am getting duplicate supervisor rows for every single employee that they supervise. If they supervise only one person, I get a singular row. If they supervise 20, I get 20 duplicate rows of that supervisor. HOWEVER, their employee that they supervise shows up in the table without issue and is properly labeled as N, no duplicates.
If anyone could help, please do! I appreciate you reading through my work, let me know if more info is required.
The usual way to achieve the desired result is like this:
select emplid, emplname,
case when emplid in (select supid from supervisor_vw) then 'Y'
else 'N' end as managerflag
from supervisor_vw;
Imagine I have a query called QueryA that returns stuff like this:
Employee Description Rank
John Happy 1
John Depressed 3
James Happy 1
James Confused 2
Mark Depressed 3
I am trying to make a query that grabs the Employee and the Description, but only one description -- the one with the best "rank." (the lower the rank the better). I sort QueryA by Employee then by Rank (descending).
So I'd want my new query QueryB to show that John as Happy, James as Happy, and Mark as Depressed.
However I try selecting Employee and then First of Description and it doesn't always work.
I'm not able to check this for Access, but it should work fine. Check my SQL Fiddle
select
r.employee, d.description
from
table1 as d
inner join (select min(rank) as rank, employee
from
table1
group by employee) r on d.rank = r.rank
and d.employee = r.employee
I want to find how many modules a lecturer taught in a specific year and want to select name of the lecturer and the number of modules for that lecturer.
Problem is that because I am selecting Name, and I have to group it by name to make it work. But what if there are two lecturers with same name? Then sql will make them one and that would be wrong output.
So what I really want to do is select name but group by id, which sql is not allowing me to do. Is there a way around it?
Below are the tables:
Lecturer(lecturerID, lecturerName)
Teaches(lecturerID, moduleID, year)
This is my query so far:
SELECT l.lecturerName, COUNT(moduleID) AS NumOfModules
FROM Lecturer l , Teaches t
WHERE l.lecturerID = t.lecturerID
AND year = 2011
GROUP BY l.lecturerName --I want lectureID here, but it doesn't run if I do that
SELECT a.lecturerName, b.NumOfModules
FROM Lecturer a,(
SELECT l.lecturerID, COUNT(moduleID) AS NumOfModules
FROM Lecturer l , Teaches t
WHERE l.lecturerID = t.lecturerID
AND year = 2011
GROUP BY l.lecturerID) b
WHERE a.lecturerID = b.lecturerID
You should probably just group by lecturerID and include it in the select column list. Otherwise, you're going to end up with two rows containing the same name with no way to distinguish between them.
You raise the problem of "wrong output" when grouping just by name but "undecipherable output" is just as big a problem. In other words, your desired output (grouping by ID but giving name):
lecturerName Module
------------ ------
Bob Smith 1
Bob Smith 2
is no better than your erroneous output (grouping by, and giving, name):
lecturerName Module
------------ ------
Bob Smith 3
since, while you now know that one of the lecturers taught two modules and the other taught one, you have no idea which is which.
The better output (grouping by ID and displaying both ID and name) would be:
lecturerId lecturerName Module
---------- ------------ ------
314159 Bob Smith 1
271828 Bob Smith 2
And, yes, I'm aware this doesn't answer your specific request but sometimes the right answer to "How do I do XYZZY?" is "Don't do XYZZY, it's a bad idea for these reasons ...".
Things like writing operating systems in COBOL, accounting packages in assembler, or anything in Pascal come to mind instantly :-)
You could subquery your count statement.
SELECT lecturername,
(SELECT Count(*)
FROM teaches t
WHERE t.lecturerid = l.lecturerid
AND t.year = 2011) AS NumOfModules
FROM lecturer l
Note there are other ways of doing this. If you also wanted to elimiate the rows with no modules you can then try.
SELECT *
FROM (SELECT lecturername,
(SELECT Count(*)
FROM teaches t
WHERE t.lecturerid = l.lecturerid
AND t.year = 2011) AS NumOfModules
FROM lecturer l) AS temp
WHERE temp.numofmodules > 0