Retrieve count of related records - sql

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'

Related

Populate SQL query with blank rows

(This is a general SQL question, but I am specifically using MSAccess 2010 so looking for how to do this with Access' flavor of SQL)
I have a table called offices which has id, office_name, num_desks.
Another table called employees which has id, employee_name.
And a final table called employee_offices which has id, office_id, employee_id.
I can assign employees to offices via employee_offices.
I am trying to generate a report which shows all offices and the employees assigned to the, but also includes blank lines for any empty desks in that office.
I realize a "simple" way to do this would be to create a desks table with id, office_id, delete the num_desks column from the offices table and change employee_offices to something like employee_desks. Then my report would be a simple LEFT OUTER JOIN and it would include all the unassigned desks. However for the sake of sanity (in this case, there is no contextual difference between desks), I am not going to do this. Plus if I start deleting desks I have referential constraints to deal with (which obviously exist for a good reason and would catch the fact that I am leaving employees without a desk), but I just want to be able to change the number of desks.
I can calculate the number of empty desks (or lack of desks) through the following command:
SELECT
office_id,
num_desks - num_employees AS desk_diff,
MAX(0, num_desks - num_employees) AS blank_rows_to_add
FROM offices LEFT OUTER JOIN (
SELECT office_id, COUNT(employee_id) AS num_employees
FROM employee_offices
GROUP BY office_Id
) AS num_employees_by_office ON offices.id = num_employees_by_office.office_id
Is there a way to take this number (blank_rows_to_add) and somehow utilze it to add that many blank rows (or at least the row only has the office_id/office_name) to a report showing a list of employees by office? I know this can be done with VBA but I am specifically looking for an SQL method that also doesn't include a temp table if at all possible.
Thank you.

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!

Retrieving duplicate and original rows from a table using sql query

Say I have a student table with the following fields - student id, student name, age, gender, marks, class.Assume that due to some error, there are multiple entries corresponding to each student. My requirement is to identify the duplicate rows in the table and the filter criterion is the student name and the class.But in the query result, in addition to identifying the duplicate records, I also need to find the original student detail which got duplicated. Is there any method to do this. I went through this answer: SQL: How to find duplicates based on two fields?. But here it only specifies how to find the duplicate rows and not a means to identify the actual row that was duplicated. Kindly throw some light on the possible solution. Thanks.
First of all: if the columns you've listed are all in the same table, it looks like your database structure could use some normalization.
In terms of your question: I'm assuming your StudentID field is a database generated, primary key and so has not been duplicated. (If this is not the case, I think you have bigger problems than just duplicates).
I'm also assuming the duplicate row has a higher value for StudentID than the original row.
I think the following should work (Note: I haven't created a table to verify this so it might not be perfect straight away. If it doesn't it should be fairly close)
select dup.StudentID as DuplicateStudentID
dup.StudentName, dup.Age, dup.Gender, dup.Marks, dup.Class,
orig.StudentID as OriginalStudentId
from StudentTable dup
inner join (
-- Find first student record for each unique combination
select Min(StudentId) as StudentID, StudentName, Age, Gender, Marks, Class
from StudentTable t
group by StudentName, Age, Gender, Marks, Class
) orig on dup.StudentName = orig.StudenName
and dup.Age = orig.Age
and dup.Gender = orig.Gender
and dup.Marks = orig.Marks
and dup.Class = orig.Class
and dup.StudentID > orig.StudentID -- Don't identify the original record as a duplicate

SQL: How do I find which movie genre a user watched the most? (IMDb personal project)

I'm currently working on a personal project and I could use a little help. Here's the scenario:
I'm creating a database (MS Access) for all of the movies myself and some friends have ever watched. We rated all of our movies on IMDb and used the export feature to get all of the movie data and our movie ratings. I plan on doing some summary analysis on Excel. One thing I am interested in is the most common movie genre that each person watched. Below is my current scenario. Note that the column "const" is the movies' unique IDs. I also have individual tables for each person's ratings and the following tables are the summary tables that make up the combination of all the movies we have watched.
Here's the table I had: http://imgur.com/v5x9Dhg
I assigned each genre an ID, like this: http://imgur.com/aXdr9XI
And here is a table where I have separate instances for each movie ID and a unique genre: http://imgur.com/N0wULo8
I want to find a way to count up all of the genres that each person watches. Any advice? I would love to provide any additional information that you need!
Thank you!
You need to have at least one table which has one row per user and const (movie watched). In the 3 example tables you posted nothing shows who watched which movies, which is information you need to solve your problem. You mention having "individual tables for each person's ratings," so I assume you have that information. You will want to combine all of them though, into a table called PERSON_MOVIE or something of the like.
So let's say your second table is called GENRE and its columns are ID, Genre.
Let's say your third table is called GENRE_MOVIE and its columns are Const and ID (ID corresponds to ID on the GENRE table)
Let's say the fourth table, which you did not post, but which is required, is called PERSON_MOVIE and its columns are person, Const, rating.
You could then write a query like this:
select vw1.*, ge.genre
from (select um.person, gm.id as genre_id, count(*) as num_of_genre
from user_movie um
inner join genre_movie gm
on um.const = gm.const
group by um.person, gm.id) vw1
inner join (select person, max(num_of_genre) as high_count
from (select um.person, gm.id, count(*) as num_of_genre
from user_movie um
inner join genre_movie gm
on um.const = gm.const
group by um.person, gm.id) x
group by person) vw2
on vw1.person = vw2.person
and vw1.num_of_genre = vw2.high_count
inner join genre ge
on vw1.genre_id = ge.id
Edit re: your comment:
So right now you have multiple tables reflecting people's ratings of movies. You need to combine those into a table called PERSON_MOVIE or something similar (as in example above).
There will be 3 columns on the table: person, const, rating
I'm not sure if access supports the traditional create table as select query but ordinarily you would be able to construct such a table in the following way:
create table person_movie as
select 'Bob', const, [You rated]
from ratings_by_bob
union all
select 'Sally', const, [You rated]
from ratings_by_sally
union all
select 'Jack', const, [You rated]
from ratings_by_jack
....
If not, just combine the tables manually and add a third column as shown indicating what users are reflected by each row. Then you can run my initial query.

Database table showing multiple results per field

Attempting to form a query using 2 tables involving member of a cycling club and their respective place in a race with Microsoft Access. When I attempt to run the following SQL code I get a query table that displays every RaceID and Member, but doesn't link each member to 1 place per race.
SELECT RaceID, LastName, FirstName, Place
FROM Members, RaceResults;
What I do wind up with is a listing for every member of the club in all places (1-10) in every race. I have attempted to do both a count function per raceID and a Join function to combine the memberID's between both tables. Neither seem to either work, or have the same result as my current table. I would appreciate any suggestions on what I am missing in my SQL Query to properly display my table.
When you join the result of 2 tables, you need to tell the database how they are linked, otherwise you'll get a cartesian product of both tables,.
Example:
SELECT t.RaceID, t.LastName, t.FirstName, tt.Place
FROM Members t join RaceResults tt on (t.RaceId = tt.RaceId);