Proper SQL Statements in a PDF? - mysql

I am in the process of creating an attendance system and have created 3 different reports to generate based on the content of 3 different MySQL tables: members, attendance, and absence.
I am having an issue though. One of the reports is working since I have the correct statement. However, I cannot get the other two to work, so I need some help on how to figure out the best SQL statement for these reports.
The first report I need has to look like this:
This report shows how many people in each precinct showed up to the event and how many excused absences are in that precinct. For this report, I will also need a "Totals" line at the very bottom to count the total number of attendees, excused absences and totals from each precinct (like this):
The second report is similar to the report that is already completed. The difference is instead of the member's email and phone address, I need to see if they were marked present and if they had an excused absence. I cannot show the report since there is real data about real people, however I can show you the SQL statement that the completed report is using:
SELECT
precinct, name, residential_address, member_email, member_phone, present, alternate
FROM
attendance INNER JOIN members ON members.id = attendance.member_id
WHERE
present = 1
ORDER BY
members.precinct
I've tried SQL COUNT statements and various JOIN queries to try and make the queries work, but nothing is working at all. What is the correct query and why?
UPDATE
Here is my table structure of the 3 tables involved in the report generation. Note that each table (other than Members) shares the Member ID column:
Members Table:
Attendance Table:
Absence Table:

This is untested against actual data, but should be close to what you're looking for.
Your first report (http://sqlfiddle.com/#!9/191d8d/1) should be:
SELECT
m.precinct as 'precinct',
COUNT(at.member_id) as 'delagates_present',
COUNT(ab.member_id) as 'delegates_absent',
COUNT(at.member_id) + COUNT(ab.member_id) as 'total'
FROM
members m
LEFT JOIN attendance at ON at.member_id = m.id
LEFT JOIN absence ab ON ab.member_id = m.id
GROUP BY
m.precinct
WITH ROLLUP;
This selects all members, groups them by precinct, counts how many were present or absent, and then adds those together for the total column. Additionally, WITH ROLLUP will give you the sums of the columns (https://dev.mysql.com/doc/refman/8.0/en/group-by-modifiers.html) as the last row.
Then your second report (http://sqlfiddle.com/#!9/191d8d/2) should be:
SELECT
precinct,
name,
residential_address,
IF(at.member_id IS NULL, 0, 1) as 'present',
IF(ab.member_id IS NULL, 0, 1) as 'absent',
alternate
FROM
members m
LEFT JOIN attendance at ON at.member_id = m.id
LEFT JOIN absence ab ON ab.member_id = m.id
ORDER BY
m.precinct,
m.id;
which selects all members and does a LEFT JOIN on the other 2 tables. Then we can use a condition in the SELECT to determine if they were present or absent. There are a number of ways that data could be represented and returned, but I've opted for a simple 1 or 0 in both of those columns.

Related

SQL Temporary Table or Select

I've got a problem with MySQL select statement.
I have a table with different Department and statuses, there are 4 statuses for every department, but for each month there are not always every single status but I would like to show it in the analytics graph that there is '0'.
I have a problem with select statement that it shows only existing statuses ( of course :D ).
Is it possible to create temporary table with all of the Departments , Statuses and amount of statuses as 0, then update it by values from other select?
Select statement and screen how it looks in perfect situation, and how it looks in bad situation :
SELECT utd.Departament,uts.statusDef as statusoforder,Count(uts.statusDef) as Ilosc_Statusow
FROM ur_tasks_details utd
INNER JOIN ur_tasks_status uts on utd.StatusOfOrder = uts.statusNR
WHERE month = 'Sierpien'
GROUP BY uts.statusDef,utd.Departament
Perfect scenario, now bad scenario :
I've tried with "union" statements but i don't know if there is a possibility to take only "the highest value" for every department.
example :
I've also heard about
With CTE tables, but I don't really get how to use it. Would love to get some tips on it!
Thanks for your help.
Use a cross join to generate the rows you want. Then use a left join and aggregation to bring in the data:
select d.Departament, uts.statusDef as statusoforder,
Count(uts.statusDef) as Ilosc_Statusow
from (select distinct utd.Departament
from ur_tasks_details utd
) d cross join
ur_tasks_status uts left join
ur_tasks_details utd
on utd.Departament = d.Departament and
utd.StatusOfOrder = uts.statusNR and
utd.month = 'Sierpien'
group by uts.statusDef, d.Departament;
The first subquery should be your source of all the departments.
I also suspect that month is in the details table, so that should be part of the on clause.

Query for joining another MySQL table, counting rows and specific fields

I'm no MySQL specialist, so I need and advice for making a single query, joining another table and counting all joined rows as well rows with specific fields
This is my initial query:
SELECT e.id, e.event_fr, e.max_capacity, count(s.id) as subscriptions
FROM events e
INNER JOIN events_subscriptions s ON s.activity = e.id
GROUP BY e.id, e.event_fr
ORDER BY e.id ASC
Basically I'm trying to find out (count) number of subscriptions for given event.
But every subscription event also has a field called "waiting_list" which can be either 0 or 1. It tells me whether or not current subscribed person is on the waiting list or not.
I need to be able to count those as well to find out how many people are on the waiting list for the given event:
id: 3,
event_fr: Yoga & relaxation,
suscriptions: 14
waiting_list: 3
id: 4,
event_fr: Judo,
suscriptions: 10
waiting_list: 5
etc..
I understand a super outer join with subquery is missing..
Is it possible to be able to additionally count "waiting_list" on joined table? (e.g WHERE waiting_list = 1)
As I see it, you don't really need that additional count, because you already know what the event's max capacity is. So, you just have to subtract the subscriptions count from the e.max_capacity value, and that is the number of people currently on the waiting list.

join 2 different tables to a third table

I have an sql issue. I have 3 tables like in the image. In the front end (User Interface), I have a selectone box to select a course and an employee autocomplete. The autocomplete must retrieve all employee names along with the status for the selected course.
I tried
select e.id,per.id,t.status
from employee e
join person per on e.personId=per.id
left join training t on e.id=t.employeeId`
but this retrieves duplicate rows for the employeeId '1'.
for the employee with id 1, I need to retireve only the row with the selected courseId (selected from User Interface. )
In short,I need all employees information plus the selected courses employee info and also empIds must not repeat.
If selected course id is 34, the retrieved output must contain
Empid,PersonName,Status
1, Ravi , 1;
2, Meera , 0;
3, Rahul ,0;
4, Vinu, 0.
How do i form the reqd sql query?
As per suggestion provided, I sort of modified the accepted answer to (as per my requirement)
SELECT e.id,per.name,COALESCE(t.status,0)
FROM employee e
JOIN person per ON e.personId=per.id
LEFT JOIN training t ON e.id=t.employeeId
AND t.courseId = ?
The trick with left joins is to add the condition on the left-joined table to the join condition:
select e.id,per.id,t.status
from employee e
join person per on e.personId=per.id
left join training t on e.id=t.employeeId
and t.courseId = ?
This only attempts joins to specific training rows.
If you put the course condition into a where clause, you lose the left join - it effectively becomes an inner join, because where clause conditions are executed after the join is made. Conditions in the join condition however are executed as the join is made.
As a general comment, many people don't realise that you can put non-key conditions into a join condition. In fact, as in this situation, it is the cleanest way to achive the output you want.

Remove duplicates from LEFT JOIN query

I am using the following JOIN statement:
SELECT *
FROM students2014
JOIN notes2014 ON (students2014.Student = notes2014.NoteStudent)
WHERE students2014.Consultant='$Consultant'
ORDER BY students2014.LastName
to retrieve a list of students (students2014) and corresponding notes for each student stored in (notes2014).
Each student has multiple notes within the notes2014 table and each note has an ID that corresponds with each student's unique ID. The above statement is returning a the list of students but duplicating every student that has more than one note. I only want to display the latest note for each student (which is determined by the highest note ID).
Is this possible?
You need another join based on the MAX noteId you got from your select.
Something like this should do it (not tested; next time I'd recommed you to paste a link to http://sqlfiddle.com/ with your table structure and some sample data.
SELECT *
FROM students s
LEFT JOIN (
SELECT MAX(NoteId) max_id, NoteStudent
FROM notes
GROUP BY NoteStudent
) aux ON aux.NoteStudent = s.Student
LEFT JOIN notes n2 ON aux.max_id = n2.NoteId
If I may say so, the fact that a table is called students2014 is a big code smell. You'd be much better off with a students table and a year field, for many reasons (just a couple: you won't need to change your DB structure every year, querying across years is much, much easier, etc, etc). Perhaps you "inherited" this, but I thought I'd mention it.
GROUP the query by studentId and select the MAX of the noteId
Try :
SELECT
students2014.Student,
IFNULL(MAX(NoteId),0)
FROM students2014
LEFT JOIN notes2014 ON (students2014.Student = notes2014.NoteStudent)
WHERE students2014.Consultant='$Consultant'
GROUP BY students2014.Student
ORDER BY students2014.LastName

Getting object if count is less then a number

I have 2 simple tables - Firm and Groups. I also have a table FirmGroupsLink for making connections between them (connection is one to many).
Table Firm has attributes - FirmID, FirmName, City
Table Groups has attributes - GroupID, GroupName
Table FirmGroupsLink has attributes - FrmID, GrpID
Now I want to make a query, which will return all those firms, that have less groups then #num, so I write
SELECT FirmID, FirmName, City
FROM (Firm INNER JOIN FirmGroupsLink ON Firm.FirmID =
FirmGroupsLink.FrmID)
HAVING COUNT(FrmID)<#num
But it doesn't run, I try this in Microsoft Access, but it eventually should work for Sybase. Please show me, what I'm doing wrong.
Thank you in advance.
In order to count properly, you need to provide by which group you are couting.
The having clause, and moreover the count can't work if you are not grouping.
Here you are counting by Firm. In fact, because you need to retrieve information about the Firm, you are grouping by FirmId, FirmName and City, so the query should look like this:
SELECT Firm.FirmID, Firm.FirmName, Firm.City
FROM Firm
LEFT OUTER JOIN FirmGroupsLink
ON Firm.FirmID = FirmGroupsLink.FrmID
GROUP BY Firm.FirmID, Firm.FirmName, Firm.City
HAVING COUNT(FrmID) < #num
Note that I replace the INNER JOIN by a LEFT OUTER JOIN, because you might want Firm which doesn't belongs to any groups too.