Creating query that finds how many redID's match to each employeeID - sql

I have a SQL Server that records employees/visitors. We have two different tables for each. I would like to display a count of how many visitors are associated with each employee. Their is a matching identifier in each table which is EmployeeID.
My tables looks like this
From Visitor
[row#][RecId][EmployeeId]
obviously other information is in their in between each of those columns.
From Employee
[row#][RecId][Id]

You can use a correlated subquery:
select e.*,
(select count(*) from visitors v where v.employeeid = e.id) as num_visitors
from employee e;

Related

SQL Query Involving Data From Different Tables

I have two different tables with records I need to join together in a way I can't quite figure out how to make work. My data looks like this.
Table A
Columns: Employee_ID, Employee_Department, Employee_Team, Manager_ID, Is_a_Manager ... many other columns
Sample Values:
12345 Department1 Team1 67890 Yes/No
.
.
.
One employee per row, several thousand rows comprising the entire company
Table B
Employee_ID, Manager_ID ... other columns
The exact same data set as Table A
Currently I'm combining those two tables (and three others) with a simple join on Employee_ID, which I'm then using as a data source in Tableau to visualize the data.
What I'd like to do with a SQL script is as follows:
Check to see whether an employee in Table A is a manager or not based on the Is_a_Manager column
If they are, find an employee in Table B who is one of their direct reports by matching the employee ID in Table A to the Manager ID in Table B.
Lookup that direct report's department and team in Table A by matching the Employee_ID in Table B to Employee_ID in Table A and displaying the Employee_Department and Employee_Team columns.
Add the direct report's department and team to two new columns in the original manager's Table A row
I'd like the final output in Table A to be something like
Employee_ID, Employee_Department, Employee_Team, Manager_ID, Is_a_Manager? ... Direct_Report_Department, Direct_Report_Team
Also, an important point is that some managers will have employees who are on different teams, so values in the Direct_Report_Department and Direct_Report_Team are not distinct. I only actually need any one employee's Department and Team to display, it doesn't matter which employee's it is.
Finally, I am able to do step 1 fairly easily in Tableau, so if the SQL script could do steps 2-4 and simply return a null value if the employee was not a manager, that would work for me as well.
Any ideas on how to accomplish this would be greatly appreciated. Thank you!
This should work based on the requirement provided. You don’t have to do any of the steps in Tableau and can simply export the output from the SQL as your data source
Select Tb1.Employee_ID, Tb1.Employee_Department, Tb1.Employee_Team, Tb1.Manager_ID, Tb1.Is_a_Manager, Tb3. Direct_Report_Department, Tb3. Direct_Report_Team
from Table_A Tb1
join (Select Manager_id, max(Employee_id) as emp_id from Table_B group by Manager_id) Tb2
on Tb1.Employee_id = Tb2.Manager_id
left join (Select Employee_ID, Employee_Department as Direct_Report_Department, Employee_Team as Direct_Report_Team from Table_A group by Employee_ID, Employee_Department, Employee_Team) Tb3
on Tb2.emp_id = Tb3.Employee_ID
where Tb1.Is_a_Manager = 'Yes';

SQL - Why Does This Happen?

These are the tables that I'm working with.
With that in mind, I want to showcase the Employees that are both a supervisor and a manager.
But when I used this
select e1.fname,e1.lname
from employee e1,employee e2,department
where e1.ssn=e2.super_ssn and e1.ssn = Mgr_ssn
This was the output
I know I can solve the problem with 'distinct', but I'm more interested to know why the output turned out like it did.
How about exists?
select e.*
from employee e
where exists (select 1 from employee e2 where e2.mgr_ssn = e.ssn) and
exists (select 1 from employee e2 where e2.super_ssn = e.ssn) ;
Your query returns duplicates for two reasons. First, presumably managers and supervisors have multiple employees below them. You end up with rows for each such employee. Second, you have a cartesian product with department, which further multiplies the rows. The department table is not used in the query.
Using select distinct is not a good solution in this case. The database just ends up having to do a lot more work than necessary -- first to create the duplicate rows and then to remove them.
add department matching clause in where like
select e1.fname,e1.lname
from employee e1,employee e2,department d
where e1.ssn=e2.super_ssn and e1.ssn = Mgr_ssn and
d.Dnumber=e1.Dno

Display all results queried on PostgreSQL where the JOINING value is missing

I have two tables on PostgreSQL, namely: employees and employers.
There is data in each of these tables.
Columns in employees: employee_id, employee_name, employer_id.
Columns in employers: employer_id, employer_name.
I want to display all employee_name's that don't have an associating employer_name.
I used the below query:
SELECT DISTINCT a.employee_name, b.employer_name
FROM employees a
NATURAL JOIN employers b
WHERE a.employee_name LIKE 'Jack';
NB!
I have also tried adding in the below to my query:
COALESCE(b.employer_name, '') = ''
Problem:
If there is no record in the employer table containing the associating employee_id value, the query returns nothing all. I am assuming this is because there is nothing for the two tables to join on?... But I would like to at least find all employees that don't have an employer. I would ideally like the employer_name value in my result to either return: blank/''/NULL.
Your assistance is greatly appreciated.
select employees.employee_name ,employers.employer_name
from employees
left join employers
on employees.employee_id = employees.employee_id
where employers.employer_name is NULL
Use a LEFT JOIN:
SELECT a.employee_name,
COALESCE(b.employer_name, 'NA') AS employer_name
FROM employees a
LEFT JOIN employers b
ON a.employer_id = b.employer_id
WHERE b.employer_id IS NULL
Your current query has several problems, first of which is that you are using a NATURAL JOIN, which should behave link an INNER JOIN, discarding employee records which do not match to any employer. Instead, by using LEFT JOIN, we can retain all employee records, regardless of whether or not they have an employer. The WHERE clause checks for NULL in the joined table, with NULL indicating that the employee did not match to any employer.
Your table name employees table is a little odd, IMO. There is a design 'rule of thumb' that says a table models either an entity or the relationship between entities but not both. To demonstrate this oddness, consider the relational operation is
employees MINUS employers
...which suggests something is off.
Another symptom of this design problem is that the employer_id in the employees table must have some kind of placeholder to represent the predicate employee has no employer, possibly a null (and nulls are to be avoided, IMO).
I suggest you fix this design by introducing a third table to model the relationship between an employee and their employer. Herein lies another design problem: shouldn't this new table be named employees? In other words, isn't the very definition of an employee a person who has an employer?
Consider this design instead:
People: person_id, person_name
Employers: employer_id, employer_name
Employees: employer_id, person_id
To find the names of people who are not employees in pseudo-relational notation:
People MINUS Employees { person_name }
SQL is quite a bit more verbose:
SELECT DISTINCT person_name
FROM People
NATURAL JOIN
( SELECT person_id FROM People
EXCEPT
SELECT person_id FROM Employees ) t;
Note your original query needlessly uses range variables a and b. One of the benefits of NATURAL JOIN is the elminiation of duplicate column names. Range variables with NATURAL JOIN always looks odd to me!

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.

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.