How to link tables correctly in SQL to add roles to staff? - sql

Currently I have a staff table with columns:
Staff_Id, first_name, Surname.
My second table is:
Id, management_role.
When I link the tables each staff member gets added to every management role. So for example a person in first table called Jim is added three times as manager, supervisor, intern and this happens for every staff.

Some things to consider that are your ID columns are primary keys for their respective tables. If not are every value in the column is unique? Also are ids not
From your description you might be using a cross join here. The thing you need is inner join so it joins the matching id's together.
So you can do
SELECT *
FROM staff_table as st
INNER JOIN management_table as mt
ON st.Staff_Id = mt.ID

Related

MS ACCESS Query with junction table, for all items in one table, but not in another

To create a many-to-many relationship, I have three tables:
tblEmployee, contains employees
tlkpPermission, contains 11 different possible permission groups an employee can be part of
tblEmployeeXPermission, combines the EmployeeID with one or more PermissionID
What I’m trying to create is a query that shows what permission groups an employee is NOT part of.
So, if EmployeeID 12345 is associated with PermissionID 1,2,3,4,5, but NOT 6,7,8,9,10,11 (in the EmployeeXPermission table) then I want the query to show EmployeeID 12345 is not part of PermissionID 6,7,8,9,10,11.
Of all the JOINs and query options, I can only get a query to show which PermissionIDs an employee is associated with, but not the PermissionIDs the employee is not associated with.
Any help would be appreciated.
Thanks
You need to start with all combinations of employees and permissions, and this type of join is CROSS JOIN, but MsAccess SQL does not have it in the new SQL syntax. You can use the old syntax of listing your tables in the FROM clause, comma separated, and provide the join condition, if any, in the WHERE clause:
SELECT
EmployeeId,
PermissionID
FROM
tblEmployee as E,
tlkpPermission as P
where not exists (
select 1
from tblEmployeeXPermission X
where X.EmployeeId=E.EmployeeId
and X.PermissionId=P.PermissionId
)
Here the part up to the WHERE clause would give you all employee - permission combinations, and the WHERE clause removes those occuring in the tblEmployeeXPermission, leaving you with the ones you want.

Access SQL Query on same table

I have two tables: one called EMP_Names which simply stores ID and Employee_Name and another table called EMP_Main which stores the main data and which refers to EMP_Names via IDs. Amongst other fields EMP_Main has fields called Technician_Name_ID and Leader_Name_ID which is related to EMP_Names. My problem is this: how can i run a query where both Technician_Name_ID and Leader_Name_ID resolve to Names? In other words both ID fields refer to the same EMP_Names.ID but I can only establish one relationship between the two tables.
Don't know if I'm clear because it's difficult to explain ...
You can use join but you need multiple joins.
select em.*, ent.name as technician, enl.name as leader
from (emp_main as em left join
emp_names as ent
on em.technician_name_id = ent.id
) left join
emp_names as enl
on em.leader_name_id = enl.id;
These are left joins in case the fields are not populated for all rows.

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.

Needing 2 different ID's from the same ID Table

I am pulling reports for my company and am needing to pull a specific report that I am having trouble with. We are using SQL Server 2012 and I am pulling the SQL reports.
What I need is to pull a simple report:
Group Name, List of Members in the group; Supervisor of the group.
However, the problem is that the supervisor as well as the members and the group name all come from one table in order to get the relevant information. Currently here is my SQL code below:
Use DATABASE
go
-- This is the select portion deciding the columns needed.
select
C.group_name
,C2.first_name
,C2.last_name
-- These are the tables that the query is pulling from.
FROM db..groups AS G
LEFT OUTER JOIN db..contact AS C
ON G.group_id=C.contact_id
INNER JOIN db..contact AS C2
ON G.member=C2.contact_id
go
This pulls the first portion:
The group name, then the first name of a member in that group, and then the last name of a member in that group.
However, I am having trouble getting the supervisor portion. This portion uses the table db.contact under the column supervisor_id as a foreign key. The supervisor_id uses the same unique id as the normal contact_id, but in the same table. Some contact_ids have supervisor_id's that are other contact_id's from the same table, hence the foreign key.
How can I make it so I can get the contact_id that is equal to the supervisor_id of the contact_id that is equal to the group_id?
Taking a quick stab at this while we wait for details
You know you need groups and I'm assuming you don't care about Groups that have no members. Thus Groups INNER JOINed to Contact. This generates your direct group membership. To get the supervisor, you then need to factor in the Supervisor on the specific Contact row.
You might not have a boss, or your boss might be yourself. It's always interesting to see how various HR systems record this. In my example, I'm assuming the head reports to no one instead of themselves.
SELECT
G.group_name
, C.first_name
, C.last_name
-- this may produce nulls depending on outer vs inner join below
, CS.first_name AS supervisor_first_name
, CS.last_name AS supervisor_last_name
FROM
dbo.Groups AS G
INNER JOIN
dbo.Contact AS C
ON C.contact_id = G.member
LEFT OUTER JOIN
dbo.Contact AS CS
ON CS.contact_id = C.supervisor_id;
Depending on how exactly you wanted that data reported, there are various tricks we could use to report that data. In particular, GROUPING SETS might come in handy.
SQLFiddle

sql: how to query foreign key not based upon ID

My table IncomingLetter has a foreign key to a table Department, which has an ID and a column Short_Name.
I'm using this query to count the incoming letters assigned to a department.
SELECT COUNT(DocumentNumber) AS TotalNumberIncomingLetters
FROM IncomingLetter
WHERE Assigned_To_Department=1;
Whereas this works I want to make a query based upon the short name and not based upon the ID.
SELECT COUNT(DocumentNumber) AS TotalNumberIncomingLetters
FROM IncomingLetter
WHERE Assigned_To_Department.Short_Name="My Department Name";
This does not work, whereas I found examples that are using this syntax. However, it is probably important to notice, that I m using this query in MS access.
You should use
SELECT COUNT(il.DocumentNumber) AS TotalNumberIncomingLetters
FROM IncomingLetter il
INNER JOIN Department d on d.ID = il.Assigned_To_Department
WHERE d.Short_Name="My Department Name";
The "My Department Name" text is actually stored in the Departments table, and only the number (1) is stored in the IncomingLetter table, in the field Assigned_To_Department.
Asking for Assigned_To_Department.Short_Name basically asks the number 1 to get it's Short_Name field, that does not make sense.
You need to tell the database engine two things in these scenarios:
which tables are connected - IncomingLetter and Departments in this case (the inner join part)
how they are connected - by setting their Assigned_To_Department and ID fields respecively (the on ... part