ACCESS: Summing all of the donations for each member - ms-access

I have simple database that stores out members and the animals they have adopted:
Member(Mem_ID, Forename, Surname, Street ... Email)
Adopted(Adopt_ID, Animal_ID, Mem_ID, Date, Amount)
Animal(Animal_ID, Name, Habitat, etc)
I'm trying to create a query that will return the total amount of donations each month made by each member.
So for example Mr Smith gives £300 to Pogo and £200 to Bobo it should return a single row with his Surname, Address and total donation (£500). It will then do this for all other members.
I can do this in PHP/SQL but cannot see how to do this easily in ACCESS.
I appreciate any support on this one!

This should do the trick:
SELECT MONTHNAME(MONTH(dDate)) AS [Month]
, Forename & ' ' & Surname AS Member
, sName AS [Animal Name]
, SUM(Amount) AS Total
FROM (Member LEFT JOIN Adopted ON Member.Mem_ID = Adopted.Mem_ID)
LEFT JOIN Animal ON Adopted.Animal_ID = Animal.Animal_ID
GROUP BY MONTHNAME(MONTH(dDate))
, Forename & ' ' & Surname
, sName
, MONTH(dDate)
ORDER BY MONTH(dDate)
I've renamed the Name and Date fields as they're reserved by Access and could cause problems.

Related

Finding the average rating of booking from each driver in a month in SQL

I'm currently taking the online class on databases, If you could help me solve this sql problem I would greatly appreciate it. Sorry I'm a complete noob.
I need to list out all the drivers’ name, age, position and their average rating for a particular month. Listing out name,age and position is ok but i have problem with the average rating(as there are few entries for a 'booking',need to calculate average from those entries) and also group them into each driver from a particular month
below are my codes
table booking
BookID NUMBER(4) PRIMARY KEY,
PersonID NUMBER(4),
driverID NUMBER(4),
PickLoc VARCHAR2(13),
DropLoc VARCHAR2(13),
TDate DATE,
TTime NUMBER(4),
RideFare CHAR(6),
TollOther CHAR(6),
cancelDate DATE,
TripRating NUMBER(1),
PayMethod CHAR(15),
table driver
driverID NUMBER(4) PRIMARY KEY,
Dname VARCHAR2(20),
DNRIC CHAR(14),
Dgender CHAR(1),
DDOB DATE,
Dmobile CHAR(11),
DcarNo CHAR(6),
Dstart DATE,
Dgrade CHAR(6),
DLicence CHAR(4),
);
This is a simple group by and apply the avg (average) function.
select Dname, timestampdiff(year,Ddob,Now()) as age,
Dgrade, avg(TripRating) as rate
from booking
inner join driver on driver.driverID = booking.driverID
where extract(year from TDate) = 2019 and
extract(month from TDate) = 1
group by Dname, timestampdiff(year,Ddob,Now()), Dgrade
It will return your averages for January 2019
PS: As #RohanKumar made me notice, my answer won't return any result for Drivers without a Booking on that period. If you want the result set to have all the drivers, even the ones without bookings, then we change the order of joining, using Driver as the main table, and changing the join for an outer join, so we return Drivers without bookings.
select Dname, timestampdiff(year,Ddob,Now()) as age,
Dgrade, avg(TripRating) as rate
from driver
left join booking on booking.driverID = driver.driverID
where extract(year from TDate) = 2019 and
extract(month from TDate) = 1
group by Dname, timestampdiff(year,Ddob,Now()), Dgrade
first you have to join your tables and select the columns you need for your calculations:
SELECT Dname, Triprating, DDOB, TDate
FROM driver, booking
WHERE booking.driverID = driver.driverID;
the drivers age is a bit tricky. According to https://stackoverflow.com/a/23824981/2331592 this could look like (assuming that you want the age at the time of the booking)
TIMESTAMPDIFF(YEAR, TDate , DDOB)
also the booking months: I would suggest to also take the year into account, maybe by formating it into '2019-06' by
DATE_FORMAT(TDate ,'%Y-%m')
so the query would now lokk like
SELECT Dname, TIMESTAMPDIFF(YEAR, TDate , DDOB) AS Dage, DATE_FORMAT(TDate ,'%Y-%m') AS Tmonth, Triprating
FROM driver, booking
WHERE booking.driverID = driver.driverID;
Now this is a table with all information and we want to group some things.
For this we need aggregate functions for the fields we do not want to group on.
I use the previous query as a sub query here. But also could be done in a single one but so it is more clear.
SELECT Dname as driver,
MAX(Dage) as age,
Tmonth as month,
AVG(Triprating) as 'average rating'
FROM (SELECT Dname,
TIMESTAMPDIFF(YEAR, TDate , DDOB) AS Dage,
DATE_FORMAT(TDate ,"%Y-%m") AS Tmonth,
Triprating
FROM driver, booking
WHERE booking.driverID = driver.driverID
)
GROUP BY driver, month
ORDER BY driver ASC, month ASC;
with light adaptions to SQLite the above SQL works and can be tried at:
https://sqliteonline.com/#fiddle-5d04d5f898b5cmzxjwxfrdws
Edit:
as Rohan Kumar in his answer suggests, the grouping of the booking data could be done before the join. this would reduce the number of rows to join and may a bit faster and less resource consuming. But in this variant the age of the driver at the booking time can not be calculated that easy.
That isn't so hard at all! You just need to join the tables, group by driver ID, then just use AVG() function method!
SQL:
SELECT Dname as driver,
TIMESTAMPDIFF(YEAR, DDOB, CUR_DATE()) as age,
Dgrade as position,
rating
FROM driver
LEFT JOIN
(SELECT driverID, AVG(TripRating) as rating
FROM booking group by driverID, MONTH(TDate)
) booking
on driver.driverID = booking.driverID
This will list out all Driver Ratings for all months, for any given month simply change the inner SQL of booking table.
That change would be so for January (Month 1):
SELECT driverID, avg(TripRating) as rating
FROM booking group by driverID
where MONTH(TDate) = 1
helpful references
https://dev.mysql.com/doc/refman/8.0/en/date-calculations.html
Using group by on multiple columns

SQL. Checking condition and marking in a column

Here is my PEOPLE table where I store name, surname, DOB (date of birth) and some other data. In a new query I need to add additional column with the condition for people with the same Name & Surname combination. Here is the condition:
Go through each group of people with the same Name & Surname combinations, in additional field mark those, whose DOB is not maximum and not minimum (compared only to same Name & Surname)
If there is only 1 or 2 occurrences of same Name & Surname, mark them anyway
Here is the result of a query
Explanation:
John Doe marked as met only once
Tom Taylor marked as met only twice
Alice Smith and Bob Brown marked everywhere except records with min and max DOB
Please help to form SQL query for the desired output. Here is my understanding (guessing)
Get list of unique Name&Surname pairs, ( where occurrences >2 ??? )
For each unique pair find rows with min and max DOB (avoid them)
In a new CheckBox column mark those that are left (not extremum)
First group by name, surname to get the number of occurrences and min and max dob of each name and surname and join the results to the table.
With a CASE statement apply the conditions:
select
p.*,
case
when g.counter in (1, 2) then 'mark'
else case
when p.dob not in (g.mindob, g.maxdob) then 'mark'
end
end Checkbox
from peaople inner join (
select
name, surname,
count(*) counter,
min(dob) mindob,
max(dob) maxdob
from people
group by name, surname
) g on g.name = p.name and g.surname = p.surname
Use window functions in MySQL 8+:
select p.*,
(case when count(*) over (partition by name, surname) <= 2
then 'mark'
when row_number() over (partition by name, surname order by dob) > 1 and
row_number() over (partition by name, surname order by dob desc) > 1
then 'mark'
end) as checkbox
from people p;
Note: If there are duplicates for the earliest or latest birthdate, this only excludes one of them. If you want to exclude all of them, use rank() instead of row_number().

Selecting sub queries using all operator without joining in mysql

I need to display the ID, Name and Date of birth from all workers from department 1 who are younger than workers from department 2. I'm trying to do with without a join.
Here's what I have at the minute, it doesn't fail when I run it but it shows all the workers from department 2, regardless of their birthday.
SELECT ID, CONCAT(fName," " ,lName) AS "Worker Name", dob
FROM Worker
WHERE dob <= ALL (SELECT department
FROM Worker
WHERE deparment = 1
)
AND deparment = 2;
You want check for dob then you should select dob
SELECT ID, CONCAT(fName," " ,lName) AS "Worker Name", dob
FROM Worker
WHERE dob <= ALL (SELECT dob
FROM Worker
WHERE deparment = 1
)
AND deparment = 2;
This should list all workers from department1 that are younger from workers in department 2:
SELECT ID, CONCAT(fName," " ,lName) AS "Worker Name", dob
FROM Worker
WHERE dob < (SELECT min(w2.dob)
FROM Worker w2
WHERE w2.deparment = 2
)
AND deparment = 1

find the number of Categories for each student

I have the following table in MySQL database:
FirstName LastName ClubName
ALAN STURGES Club1
ALESIA BLACKBURN Club2
ALESIA BLACKBURN, 'Club 3'
I want to find out the number of clubs that each student is in.then I want to consolidate the report and show just the count of students based on the number of clubs they are in.
example:
students Number of Clubs
20 1
40 2
The GROUP BY and COUNT() clauses will be your heroes.
/*Knowing the number of clubs per student*/
SELECT COUNT(id) FROM your_tbl GROUP BY col_student_id;
and
/*Knowing the number of students per club*/
SELECT COUNT(id) FROM your_tbl GROUP BY col_club_id;
Modify the above queries to suits your need results. For more information about it, read it here https://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html
i guess
SELECT CONCAT(FirstName, ' ', LastName) as FULLNAME, COUNT(*)
FROM TABLENAME
GROUP BY FULLNAME;

Simple SQL Ordering Question

If I had the following relation
Staff (staffNo(PK), fName, lName, position, sex, DOB)
How would I go about writing a query which produced a list of all details of all female staff ordered by their second name then their first name?
My guess is:
SELECT * FROM Staff ORDER BY fName ASC, lName ASC WHERE sex = 'f'
Is this correct?
Well, you can try this out to see if this is correct :)
But you should swap where predicate with order by clause, and ordering predicates as well: if you want to sort by the last name at first - you should specify last name first in the order by.
SELECT * FROM staff WHERE sex = 'F' ORDER BY lName ASC, fName ASC
You had fName and lName the wrong way round, and your ORDER BY comes after the WHERE
Try this query:
SELECT * FROM Staff WHERE sex = 'f' order by lName, fName;