Very basic question re Many to Many queries MS-Access - ms-access-2007

Apologies in advance for the banal and basic nature of this question, but I'm brand new to Access. I've searched my Access books and bibles, online, etc and cannot solve this very simple problem:
I have a many to many relationship set up for Employees and Events they may attend. An employee can attend many events. An event can be attended by many employees. I have no trouble writing a query to list Employees who have been on - say - Event A OR Event C. What I can't do is write a query to list employees who have been on (for example) Event A AND Event C.
I have three tables:
Employee. Key: EmployeeId. (Also contains name, position, etc)
EmployeeEvent. Keys: ID, EmployeeID
Event. Key:EventID (Also contains event name, date etc)
Employee links to EmployeeEvent on Employee.EmployeeID=EmployeeEvent.EmployeeID
Event links to EmployeeEvent on Event.EventID=EmployeeEvent.ID
No problem with OR queries. Simply don't know how to make AND queries work.
This is my first ever post, many thanks in advance for your help!

A brute force way would be to do a union:
Select employeeID, EventID from EmployeeEvent
where employeeID = 9999999 and eventID = 8888
Union
Select employeeID, EventID from EmployeeEvent
where employeeID = 9999999 and eventID = 7777
The "Union" will get rid of any duplicates in the results. "Union All" will preserve any duplicates.
This query will not show up in your visual query editor. It will say something like "Cannot display", but it should run.
You could also do two select queries, one for each Employee/Event combination you're looking for, then link the two queries in an inner join. The employees who went to both events should show in the results. Just depends on how you want to see your results.

Related

How do I select mothers in the table that have children of all the listed genders? (implementing RA Division in SQL)

I have a table (person) with the following columns:
name, gender, mother
and I need to extract the names of the mothers who have a baby of every gender. I'm not allowed to assume that gender is limited to just M and F.
I can do SELECT DISTINCT person.gender FROM person to get a list of all genders present in the table.
I also created a table with all the names of the mothers and their child's gender as the two columns.
The problem is, I have no idea how to check if a mother has had a child of all respective genders in the table. How can I implement this?
Edit: How I achieved my final solution can be found below, thank you all for your answers! I have also updated the title to help others find it.
Group the mothers' records together, and in each group count how many distinct genders there are.
SELECT
mother
FROM
person
GROUP BY
mother
HAVING
COUNT(DISTINCT gender) = (SELECT COUNT(DISTINCT gender) FROM person)
I ultimately approached the issue the same as #MatBailie but found it useful to include the COUNT in the final query as well. You basically need two things to make this type of query work. 1) A collection of distinct mothers, 2) The number of distinct genders. A GROUP BY and an aggregate subquery works nicely here.
SELECT COUNT(DISTINCT gender) AS genderCount, mother FROM person
GROUP BY mother
HAVING genderCount = (SELECT COUNT(DISTINCT gender) from person);
In the end I implemented the relational algebra division method into SQL using various EXCEPT and IN conditions. Relational algebra division works great when you have two columns, where some kind of label (e.g. a name) is connected to some type (e.g. gender), and you wish to find if a specific label is linked to all types that are specified in another, separate table.
In my case the list of labels were the names of the mothers, and their associated type was the gender of their child. Using the SELECT statement I created in my question post, this gave me a list of genders where each mother must have for my query. This was my "type" table, that all the mothers had to link to.
This is how I got the answer to my question in the end.
A nice, detailed guide on how to implement it is here:
https://www.geeksforgeeks.org/sql-division/
The other answers do also work and are much simpler, but this solution feels more general and I think it should be shared!

Looking to display records from Table A that have more than one relationship to Table B

This sounds like a very simple query but I have never needed this calculation before. I'm using SQL Management Studio and SQL Server 2008.
I have a table ct_workers which contains individual employees and a second table cs_facilities which shows the sites that they work at.
The table ct_workers has a field person which is the primary ID for each employee and has a field facility which links the employees to cs_facilities via a field guid
I'm looking to display all workers that have 2 or more facilities.
I've though about using Excel or rownumber but surely that must be a simple efficient way of doing this?
Can anyone assist please?
Thanks,
You can use a GROUP BY with HAVING
SELECT cw.person
FROM ct_workers cw
GROUP BY cw.person
HAVING COUNT(DISTINCT cw.facility) >= 2
Your question suggests that you can use aggregation:
select w.person
from ct_workers w
group by w.person
having min(w.facility) <> max(w.facility); -- at least 2 values
However, if the person is the unique key in ct_workers, then a person can only be in one facility. So, your question would not make sense. You should actually have a junction table with one row per person and per facility.

Purpose of Self-Joins

I am learning to program with SQL and have just been introduced to self-joins. I understand how these work, but I don't understand what their purpose is besides a very specific usage, joining an employee table to itself to neatly display employees and their respective managers.
This usage can be demonstrated with the following table:
EmployeeID | Name | ManagerID
------ | ------------- | ------
1 | Sam | 10
2 | Harry | 4
4 | Manager | NULL
10 | AnotherManager| NULL
And the following query:
select worker.employeeID, worker.name, worker.managerID, manager.name
from employee worker join employee manager
on (worker.managerID = manager.employeeID);
Which would return:
Sam AnotherManager
Harry Manager
Besides this, are there any other circumstances where a self-join would be useful? I can't figure out a scenario where a self-join would need to be performed.
Your example is a good one. Self-joins are useful whenever a table contains a foreign key into itself. An employee has a manager, and the manager is... another employee. So a self-join makes sense there.
Many hierarchies and relationship trees are a good fit for this. For example, you might have a parent organization divided into regions, groups, teams, and offices. Each of those could be stored as an "organization", with a parent id as a column.
Or maybe your business has a referral program, and you want to record which customer referred someone. They are both 'customers', in the same table, but one has a FK link to another one.
Hierarchies that are not a good fit for this would be ones where an entity might have more than one "parent" link. For example, suppose you had facebook-style data recording every user and friendship links to other users. That could be made to fit in this model, but then you'd need a new "user" row for every friend that a user had, and every row would be a duplicate except for the "relationshipUserID" column or whatever you called it.
In many-to-many relationships, you would probably have a separate "relationship" table, with a "from" and "to" column, and perhaps a column indicating the relationship type.
I found self joins most useful in situations like this:
Get all employees that work for the same manager as Sam. (This does not have to be hierarchical, this can also be: Get all employees that work at the same location as Sam)
select e2.employeeID, e2.name
from employee e1 join employee e2
on (e1.managerID = e2.managerID)
where e1.name = 'Sam'
Also useful to find duplicates in a table, but this can be very inefficient.
There are several great examples of using self-joins here. The one I often use relates to "timetables". I work with timetables in education, but they are relevant in other cases too.
I use self-joins to work out whether two items clash with one another, e.g. a student is scheduled for two lessons which happen at the same time, or a room is double booked. For example:
CREATE TABLE StudentEvents(
StudentId int,
EventId int,
EventDate date,
StartTime time,
EndTime time
)
SELECT
se1.StudentId,
se1.EventDate,
se1.EventId Event1Id,
se1.StartTime as Event1Start,
se1.EndTime as Event1End,
se2.StartTime as Event2Start,
se2.EndTime as Event2End,
FROM
StudentEvents se1
JOIN StudentEvents se2 ON
se1.StudentId = se2.StudentId
AND se1.EventDate = se2.EventDate
AND se1.EventId > se2.EventId
--The above line prevents (a) an event being seen as clashing with itself
--and (b) the same pair of events being returned twice, once as (A,B) and once as (B,A)
WHERE
se1.StartTime < se2.EndTime AND
se1.EndTime > se2.StartTime
Similar logic can be used to find other things in "timetable data", such as a pair of trains it is possible to take from A via B to C.
Self joins are useful whenever you want to compare records of the same table against each other. Examples are: Find duplicate addresses, find customers where the delivery address is not the same as the invoice address, compare a total in a daily report (saved as record) with the total of the previous day etc.

Retrieve count of related records

I currently have two tables in my data source that I'm referencing in this instance.
Firstly, to explain the context, I have a windows form program in VB.NET (Visual Studio 2013).
In the first table Trainer, I have the following fields : ID, First Name, Surname, Contact, Class.
In the second table Member, I have the following fields : ID, First Name, Surname, Contact, Type, TrainerID.
I have enforced referential integrity between the two tables using Trainer.ID as PK and Member.TrainerID as FK with a 1:m relationship. I'm trying to retrieve the count of related records, to the specified ID of the trainer. I want to retrieve the count of related records. So, for example on the form I click Search and provide a trainer ID, I'd like to return the amount of customers he/she has belonging to them.
I need that, so that I can work out their salary based on commission + base amount.
I've looked around a lot, read up a lot but I just can't seem to get it. Any help whatsoever will be appreciated.
If you have the trainer id, can't you just do:
select count(*) as cnt
from member m
where m.trainerid = #TheTrainerId;
select count(m.id) as count_members
from trainer t
left join member m on m.trainerid = t.id
where t.surname = 'watson'

How to create views against a hierarchical table

I am learning how to create view using SQL server. I am trying to add a view called Managers in the Northwind database that shows only employees that supervise other employees. This is what I have so far.
Create View Manager_vw
As
Select LastName,
FirstName,
EmployeeID
From Employees
Where
What I am stuck on is how and I going to put in supervise other employees. I am not to sure how to do this. If someone can help me understand how to do this.
In northwind.dbo.employees you would find employees who supervise other employees by looking the reportsto column. Basically you want to return employees whose id is in the reportsto column in another row. That can be done like this:
SELECT LastName,
FirstName,
EmployeeID
FROM employees E
WHERE EXISTS(SELECT * FROM Employees WHERE reportsTo = E.EmployeeID)
The EXISTS is like a JOIN but is usually implemented as a "semi-join" which will stop processing after it finds a singe match (rather than finding all the subordinate employees which would take extra work) Because it doesn't return any additional records, you also save the cost of the additional step to eliminate duplicates (a JOIN would do more work to process the join, and even more work to undo the work that wasn't necessary by doing a DISTINCT.)
You'll notice that I reference E.EmployeeID in the subquery, which relates the subquery to the outer query, this is called a Correlated Subquery.
A word of caution: Views have their place in a DB but can easily be misused. When an engineer comes to the database from an OO background, views seem like a convenient way to promote inheritance and reusability of code. Often people eventually find themselves in a position where they have nested views joined to nested views of nested views. SQL processes nested views by essentially taking the definition of each individual view and expanding that into a beast of a query that will make your DBA cry.
Also, you followed excellent practice in your example and I encourage you to continue this. You specified all your columns individually, never ever use SELECT * to specify the results of your view. It will, eventually, ruin your day. You'll see I do have a SELECT * in my EXISTS clause but EXISTS does not return a resultset and the optimizer will ignore that in that specific case.
Here's another option:
SELECT DISTINCT manager_tbl.*
FROM Employees AS staff_tbl
JOIN Employees AS manager_tbl
ON staff_tbl.ReportsTo = manager_tbl.EmployeeID
Adapted from this site. There are a number of example queries there that you might find interesting and useful.
Notes:
Using the DISTINCT keyword because a single manager could have more than one direct report. DISTINCT will omit the repetition caused by such a one-to-many relationship.
The Employees table in the Northwind database is an example of a hierarchical relationship modeled in a single table.
All together:
CREATE VIEW Manager_vw
AS
SELECT DISTINCT manager_tbl.*
FROM Employees AS staff_tbl
JOIN Employees AS manager_tbl
ON staff_tbl.ReportsTo = manager_tbl.EmployeeID