SQL Count aggregate question, combining 3 tables - sql

I am trying to join 3 tables to include only those employees who are assigned to more than one assignment. Through troubleshooting, I have found that my query works until I add my third table. Specifically, until I add the third table's columns to group by.
I need the third table added, as it included the start and end date of the projects.
I have been at this for days.
I have tried string_agg to bypass using the columns from the third table in the group by, but found that it it not supported in the program we're required to use.
I have tried different joins, different counts, using variables. I have tried joining the tables in different combinations and subsequently worked through other errors. I have tried to do nested select statements.
At this point, I have lost count. I started out with a cartesian product and have now worked out that I think the problem lies somewhere with grouping third(projects) table.
CREATE VIEW Assignments AS
SELECT a.EmpIDNumber,
COUNT(*) AS Frequency,
e.FirstName,
e.LastName,
a.PositionOnProject,
P.AssignedToProject AS ProjectName,
P.ProjectBeginDate AS StartDate,
P.FinishOnProject AS End_Date
FROM Assignments a
INNER JOIN Employees e ON a.EmpIDNumber = e.EmpIDNumber
INNER JOIN Projects p ON a.projectID = p.ProjectID
GROUP BY e.FirstName,
E.LastName,
a.PositionOnProject,
a.EmpIDNumber,
p.AssignedToProject,
p.ProjectBeginDate,
p.FinishOnProject
HAVING COUNT(*) > 1;
As is, I get no results. Just empty headers.
Removing the third table(projects) from the select and group by, I get the expected results, showing those employees who are assigned to more than one project.
I know I am doing something wrong and am open and eager to learn what that is. Any help in doing that is appreciated.

If you want project details for employees assigned to more than one project, then use window functions:
SELECT a.EmpIDNumber, a.Frequency,
e.FirstName, e.LastName, a.PositionOnProject,
P.AssignedToProject AS ProjectName,
P.ProjectBeginDate AS StartDate,
P.FinishOnProject AS End_Date
FROM (SELECT a.*, COUNT(*) OVER (PARTITION BY a.EmpIDNumber) as frequency
FROM Assignments a
) a INNER JOIN
Employees e
ON a.EmpIDNumber = e.EmpIDNumber INNER JOIN
Projects p
ON a.projectID = p.ProjectID
WHERE frequency > 1;
Your problem is that you have added the project information to the GROUP BY. Only one project is going to match those conditions, so the HAVNG clause ends up filtering everything out.

Related

Postgres Join 3 Tables(Timestamp)

I have 3 tables and need mutliple values from them. I need pname(project), lead(project), author(changegroup) and updated(jiraissue)/created(changegroup). pname and lead are project name and leader of the project. Author is the one who changed the ticket the last time, and update and created are the timestamps from that action. But update and created are often not the same. So cant use them to filter. I have no problem to get pname, lead, and update. But I need the author too.
SELECT pname, lead, MAX(updated) FROM project join jiraissue on project.id=jiraissue.project GROUP BY(pname, lead);
That is the query command to get pname, lead, and updated. I filter the all tickets from a project, and look which was edited the most recently. I take that timestamp for the time the entire project was edited the last time. But couldn't create an command to get the author too. you help me?
Project Table:
The Project itself with project name and lead| public.id=jiraissue.project
Jira Issue Table:
jiraissues are all tickets from the projects |project.id=jiraissue.project, jiraissue.updated is most times changegroup.created, changegroup.issueid=jiraissue.id
Changegroup Table:
changegroup is a list of the times when a ticket is edited| changegroup.issueid=jiraissue.id, changegroup.created=jiraissue.updated
Your explanation left me confused. But here is my educated guess:
SELECT p.pname, p.lead, c.author, j.updated, c.created
FROM project p
LEFT JOIN (
SELECT DISTINCT ON (j.project)
j.project, j.updated, j.id
FROM jiraissue j
ORDER BY j.project, j.updated DESC NULLS LAST
) j ON j.project = p.id
LEFT JOIN changegroup c ON c.issueid = j.id;
Another case for DISTINCT ON. See:
Select first row in each GROUP BY group?
Eliminating unneeded rows before joining should be the fastest way.
I use 2x LEFT JOIN retain projects without any Jira issues in the result.

Ms-Access: counting from 2 tables

I have two tables in a Database
and
I need to retrieve the number of staff per manager in the following format
I've been trying to adapt an answer to another question
SELECT bankNo AS "Bank Number",
COUNT (*) AS "Total Branches"
FROM BankBranch
GROUP BY bankNo
As
SELECT COUNT (*) AS StaffCount ,
Employee.Name AS Name
FROM Employee, Stafflink
GROUP BY Name
As I look at the Group BY I'm thinking I should be grouping by The ManID in the Stafflink Table.
My output with this query looks like this
So it is counting correctly but as you can see it's far off the output I need to get.
Any advice would be appreciated.
You need to join the Employee and Stafflink tables. It appears that your FROM clause should look like this:
FROM Employee INNER JOIN StaffLink ON Employee.ID = StaffLink.ManID
You have to join the Eployee table twice to get the summary of employees under manager
select count(*) as StaffCount,Manager.Name
from Employee join Stafflink on employee.Id = StaffLink.EmpId
join Employee as Manager on StaffLink.ManId = Manager.Id
Group by Manager.Name
The answers that advise you on how to join are correct, assuming that you want to learn how to use SQL in MS Access. But there is a way to accomplish the same thing using the ACCESS GUI for designing queries, and this involves a shorter learning curve than learning SQL.
The key to using the GUI when more than one table is involved is to realize that you have to define the relationships between tables in the relationship manager. Once you do that, designing the query you are after is a piece of cake, just point and click.
The tricky thing in your case is that there are two relationships between the two tables. One relationship links EmpId to ID and the other links ManId to ID.
If, however, you want to learn SQL, then this shortcut will be a digression.
If you don't specify a join between the tables, a so called Cartesian product will be built, i.e., each record from one table will be paired with every record from the other table. If you have 7 records in one table and 10 in the other you will get 70 pairs (i.e. rows) before grouping. This explains why you are getting a count of 7 per manager name.
Besides joining the tables, I would suggest you to group on the manager id instead of the manager name. The manager id is known to be unique per manager, but not the name. This then requires you to either group on the name in addition, because the name is in the select list or to apply an aggregate function on the name. Each additional grouping slows down the query; therefore I prefer the aggregate function.
SELECT
COUNT(*) AS StaffCount,
FIRST(Manager.Name) AS ManagerName
FROM
Stafflink
INNER JOIN Employee AS Manager
ON StaffLink.ManId = Manager.Id
GROUP BY
StaffLink.ManId
I don't know if it makes a performance difference, but I prefer to group on StaffLink.ManId than on Employee.Id, since StaffLink is the main table here and Employee is just used as lookup table in this query.

SQL Maximum number of doctors in a department

my problem is this:
I have a table named
Doctor(id, name, department)
and another table named
department(id, name).
a Doctor is associated with a department (only one department, not more)
I have to do a query returning the department with the maximum number of doctors associated with it.
I am not sure how to proceed, I feel like I need to use a nested query but I just started and I'm really bad at this.
I think it should be something like this, but again I'm not really sure and I can't figure out what to put in the nested query:
SELECT department.id
FROM (SELECT FROM WHERE) , department d, doctor doc
WHERE doc.id = d.id
A common approach to the "Find ABC with the maximum number of XYZs" problem in SQL is as follows:
Query for a list of ABCs that includes each ABC's count of XYZs
Order the list in descending order according to the count of XYZs
Limit the result to a single item; that would be the top item that you need.
In your case, you can do it like this (I am assuming MySQL syntax for taking the top row):
SELECT *
FROM department dp
ORDER BY (SELECT COUNT(*) FROM doctor d WHERE d.department_id=dp.id) DESC
LIMIT 1
You can use Group BY
Select top (1) department.id,count(Doctor.*) as numberofDocs
from department inner join Doctor on Doctor.id = department.id
Group by department.id
Order by count(Doctor.*) desc
I generally avoid using sub queries in MySQL due to a well known bug in MySQL. Due to the bug, MySQL executes the inner query for every single outer query result. Therefore, if you have 10 departments, then doctor query would be executed 10 times. The bug may have been fixed in MySQL 5.6. In this particular case the number of departments may not be large, therefore performance may not be your main concern. However, the following solution should work for MySQL and much more optimized. The answer by dasblinkenlight is almost the same, just got ahead of me :). But MySQL does not support the command top.
select dep.id, dep.name, count(doc.id) as dep_group_count from Doctor doc join department dep on doc.department = dep.id group by doc.department order by dep_group_count DESC LIMIT 1

Counting number of occurrences in subquery

My task is to find the number of occurrences of late timesheet submissions for each employee in our database. There are two tables which I have primarily been looking at, but I'm having trouble putting the two together and coming up with a decent view of the COUNT of occurrences and the employee ID for which they are associated with.
I have created this query which provides me with the EmployeeID for each occurrence.
SELECT db.Employee.EmployeeID
FROM db.LateTimesheets
INNER JOIN db.Employee ON Employee.LastName = LateTimesheets.LastName AND Employee.FirstName = Late Timesheets.FirstName
Now, with this simple query I have a view of the EmployeeID repeated however many times these incidents have occured. However, what I ultimately want to end up with is a table that displays a count for each occurance, along with the EmployeeID for which this count is associated with.
I would assume I would need to use the COUNT() function to count the amount of rows for each EmployeeID, and then select that value along with EmployeeID. However, I am having trouble structuring the subquery correctly, and everything I have tried thus far has only generated errors with MS SQL Server Management Studio.
A simpler version of usr's answer would be the following which avoids the construction of the derived table:
Select db.Employee.EmployeeID, Count( db.LateTimesheets.somecolumn ) As Total
From db.Employee
Left Join db.LateTimesheets
On LateTimesheets.LastName = Employee.LastName
And Late Timesheets.FirstName = Employee.FirstName
Group By db.Employee.EmployeeID
I may have misunderstood the question, but wouldn't GROUP BY solve your problem?
SELECT COUNT(db.LateTimesheets.somecolumn), db.Employee.EmployeeID
FROM db.LateTimesheets
INNER JOIN db.Employee ON Employee.LastName = LateTimesheets.LastName
AND Employee.FirstName = Late Timesheets.FirstName
GROUP BY db.Employee.EmployeeID
Just replace somecolumn with the name of a column that's actually in the table.
select e.*, isnull(lt.Count, 0) as Count
from Employee e
left join (
select LastName, count(*) as Count from LateTimesheets
) LateTimesheets lt on e.LastName = lt.LastName
The trick is to do the grouping in a derived table. You don't want to group everything, just the LateTimesheets.
We need a left join to still get employees with no LateTimesheets.

MySQL Select Statement - Two Tables, Sort One Table by Count of Other Table

So I have built a voting system for a custom post system i wrote.
I want to be able to sort by "most voted", "Most liked", etc.
I have two tables.
Entry: ID, Title, Post
Vote: ID, EntryID, Result
I want to be able to query the vote table for each entry and see how many vote's there are, and then sort the entry's by how many vote's each table had. I have messed around with joins, etc. and cannot seem to figure it out. Any suggestions?
You want to make a join and group by the entry items, then use aggregates like count and sum to get the number of votes and the sum of votes:
select e.ID, e.Title, e.Post, count(*) as Votes, sum(Result) as Result
from Entry e
inner join Vote v on v.EntryId = e.Id
group by e.ID, e.Title, e.Post
order by 4 desc