How to run two SQL queries together? - mysql

I have two sql queries I want to run at once so I don't have to run twice to get the result
SELECT COUNT(*) FROM attendance WHERE month =10 and grade = 4
SELECT COUNT(*) from attendance WHERE month = 10 and grade = 4 AND userid = 24 and attendance = 'present'
I want two counts of total class and total number of classes in which student is present.

You can combine the second criteria using conditional aggregation, this way the table is only read once.
select
Count(*) as TotalCount,
Count(case when userid = 24 and attendance = 'present' then 1 end) as StudentCount
from attendance
where month = 10 and grade = 4;

Related

Split column conditionally

I want to split a column based on if a condition is true or false and count the number of patients in each category for each doctor
This is my code:
SELECT p.MRP_CP_ID, COUNT(p.PTNT_ID) FROM PATIENT p
JOIN PATIENT_SCHEDULE ps ON ps.PTNT_ID = p.PTNT_ID
WHERE ps.MLTPL_PHRM_FLG = 0
GROUP BY MRP_CP_ID;
But i want to display the count of patients for where the MLTPL_PHRM_FLG is 1 in another column. Is there an easy way to do this?
current result from that displayed here
This can be done with conditional aggregation.
SELECT p.MRP_CP_ID,
COUNT(*) Total,
COUNT(CASE WHEN ps.MLTPL_PHRM_FLG = 0 then 1 END) as PHRM_FLG_0_Counts,
COUNT(CASE WHEN ps.MLTPL_PHRM_FLG = 1 then 1 END) as PHRM_FLG_1_Counts
FROM PATIENT p
JOIN PATIENT_SCHEDULE ps ON ps.PTNT_ID = p.PTNT_ID
GROUP BY MRP_CP_ID;

Select count of customers that purchased at least one from two specific categories in the same month

I'm trying to write a query to count the customers that purchased at least one from order_type=0 and one order_type=1 during the same month in 2014
I have two tables.
The order table that have:
order_id
customer_id
aquisition_date
orders_category table:
order_id
order_type (the type of the orders it may have 0, 1, 2, 3, 5, 8 ...etc )
I tried with this query but it didn't work, I know it's not complete and I missed the month condition!
Select count(user_id) From order
join orders_category
on order.order_id = orders_category.order_id
Where (order_type=0 or order_type=1)
and extract (year from order.aquisition_date)=2014
group by user_id
having count (case when type_id=0 then null else null end) > 0
and count (case when type_id=1 then null else null end) > 0;
I don't know how to find users with at least 1 order from order_type=0 & 1 order of order_type=1, in the same month.
You could use this query, based on what you already had. However, I suggest you change the name of the table order to orders as order is a reserved word:
select count(distinct user_id)
from (
select user_id, month(aquisition_date)
from orders
inner join order_category
on orders.order_id = order_category.order_id
where order_type in (0, 1)
and year(aquisition_date) = 2014
group by user_id, month(aquisition_date)
having count(distinct order_type) = 2
) as base
SQL fiddle
I selected the month also in the sub-select, as it will be interesting to look at the output of that query on its own during your analysis.

SQL How to create a value for a new column based on the count of an existing column by groups?

I have a temp table that I'm reading from, and I want to look at one of the columns that only has two grade values - either a 3 or a 4 and build two new columns - one that holds the count of the 3's and the other to hold the count of the 4's - by a particular grouping. My code looks like this.
Select Max(Counting) as Total
, student
, stdType
, Score3 = (SELECT count(*) from #tempBWMSHonors3 where score = '3')
, Score4 = (SELECT count(*) from #tempBWMSHonors3 where score = '4')
from #tempBWMSHonors3
group by student, stateID, grade, stdType
I also embedded an image that show an example of my temp table and what I'm trying to achieve (as well as the result I am getting - but don't want).
[]
I think you just want conditional aggregation, not subqueries:
select Max(Counting) as Total, student, stdType,
sum(case when score = '3' then 1 else 0 end) as Score3,
sum(case when score = '4' then 1 else 0 end) as Score4
from #tempBWMSHonors3
group by student, stdType;
Note: if score is a number and not a string, then you should not use single quotes for the constant.

Count DISTINCT on a single column over multiple conditions

I have a table, and I want to get the DISTINCT count of usernames over a certain period of time. Currently I'm running this query
SELECT DISTINCT username FROM user_activity WHERE company_id = 9 AND timestamp BETWEEN '2015-09-00' AND '2015-10-01' AND action = "Login Success";
It works great, however, I have multiple Companies that I want to select the count for. How do I expand the previous query to show me the distinct counts for multiple companies?
select count(distinct username),
sum(case when company_id = 1 then 1 else 0 end) A,
sum(case when company_id = 9 then 1 else 0 end) B
from `user_activity` Where timestamp BETWEEN '2015-09-00' AND '2015-10-01' AND action = "Login Success"
I've done something like this, however, I'm not getting the correct numbers. Ideally I would like to list each count as a different value for ease of reading, like the previous query illustrates. I don't need the count(distinct username) column to appear in my result, just the conditionals.
Thanks in advance.
If you don't mind two rows instead of two columns:
SELECT company_id, COUNT(DISTINCT username)
FROM user_activity
WHERE company_id IN (1,9)
AND timestamp >= '2015-09-01'
AND timestamp < '2015-09-01' + INTERVAL 1 MONTH
AND action = "Login Success"
GROUP BY company_id

SQL query that reports N or more consecutive absents from attendance table

I have a table that looks like this:
studentID | subjectID | attendanceStatus | classDate | classTime | lecturerID |
12345678 1234 1 2012-06-05 15:30:00
87654321
12345678 1234 0 2012-06-08 02:30:00
I want a query that reports if a student has been absent for 3 or more consecutive classes. based on studentID and a specific subject between 2 specific dates as well. Each class can have a different time. The schema for that table is:
PK(`studentID`, `classDate`, `classTime`, `subjectID, `lecturerID`)
Attendance Status: 1 = Present, 0 = Absent
Edit: Worded question so that it is more accurate and really describes what was my intention.
I wasn't able to create an SQL query for this. So instead, I tried a PHP solution:
Select all rows from table, ordered by student, subject and date
Create a running counter for absents, initialized to 0
Iterate over each record:
If student and/or subject is different from previous row
Reset the counter to 0 (present) or 1 (absent)
Else, that is when student and subject are same
Set the counter to 0 (present) or plus 1 (absent)
I then realized that this logic can easily be implemented using MySQL variables, so:
SET #studentID = 0;
SET #subjectID = 0;
SET #absentRun = 0;
SELECT *,
CASE
WHEN (#studentID = studentID) AND (#subjectID = subjectID) THEN #absentRun := IF(attendanceStatus = 1, 0, #absentRun + 1)
WHEN (#studentID := studentID) AND (#subjectID := subjectID) THEN #absentRun := IF(attendanceStatus = 1, 0, 1)
END AS absentRun
FROM table4
ORDER BY studentID, subjectID, classDate
You can probably nest this query inside another query that selects records where absentRun >= 3.
SQL Fiddle
This query works for intended result:
SELECT DISTINCT first_day.studentID
FROM student_visits first_day
LEFT JOIN student_visits second_day
ON first_day.studentID = second_day.studentID
AND DATE(second_day.classDate) - INTERVAL 1 DAY = date(first_day.classDate)
LEFT JOIN student_visits third_day
ON first_day.studentID = third_day.studentID
AND DATE(third_day.classDate) - INTERVAL 2 DAY = date(first_day.classDate)
WHERE first_day.attendanceStatus = 0 AND second_day.attendanceStatus = 0 AND third_day.attendanceStatus = 0
It's joining table 'student_visits' (let's name your original table so) to itself step by step on consecutive 3 dates for each student and finally checks the absence on these days. Distinct makes sure that result willn't contain duplicate results for more than 3 consecutive days of absence.
This query doesn't consider absence on specific subject - just consectuive absence for each student for 3 or more days. To consider subject simply add .subjectID in each ON clause:
ON first_day.subjectID = second_day.subjectID
P.S.: not sure that it's the fastest way (at least it's not the only).
Unfortunately, mysql does not support windows functions. This would be much easier with row_number() or better yet cumulative sums (as supported in Oracle).
I will describe the solution. Imagine that you have two additional columns in your table:
ClassSeqNum -- a sequence starting at 1 and incrementing by 1 for each class date.
AbsentSeqNum -- a sequence starting a 1 each time a student misses a class and then increments by 1 on each subsequent absence.
The key observation is that the difference between these two values is constant for consecutive absences. Because you are using mysql, you might consider adding these columns to the table. They are big challenging to add in the query, which is why this answer is so long.
Given the key observation, the answer to your question is provided by the following query:
select studentid, subjectid, absenceid, count(*) as cnt
from (select a.*, (ClassSeqNum - AbsentSeqNum) as absenceid
from Attendance a
) a
group by studentid, subjectid, absenceid
having count(*) > 2
(Okay, this gives every sequence of absences for a student for each subject, but I think you can figure out how to whittle this down just to a list of students.)
How do you assign the sequence numbers? In mysql, you need to do a self join. So, the following adds the ClassSeqNum:
select a.StudentId, a.SubjectId, count(*) as ClassSeqNum
from Attendance a join
Attendance a1
on a.studentid = a1.studentid and a.SubjectId = a1.Subjectid and
a.ClassDate >= s1.classDate
group by a.StudentId, a.SubjectId
And the following adds the absence sequence number:
select a.StudentId, a.SubjectId, count(*) as AbsenceSeqNum
from Attendance a join
Attendance a1
on a.studentid = a1.studentid and a.SubjectId = a1.Subjectid and
a.ClassDate >= a1.classDate
where AttendanceStatus = 0
group by a.StudentId, a.SubjectId
So the final query looks like:
with cs as (
select a.StudentId, a.SubjectId, count(*) as ClassSeqNum
from Attendance a join
Attendance a1
on a.studentid = a1.studentid and a.SubjectId = a1.Subjectid and
a.ClassDate >= s1.classDate
group by a.StudentId, a.SubjectId
),
a as (
select a.StudentId, a.SubjectId, count(*) as AbsenceSeqNum
from Attendance a join
Attendance a1
on a.studentid = a1.studentid and a.SubjectId = a1.Subjectid and
a.ClassDate >= s1.classDate
where AttendanceStatus = 0
group by a.StudentId, a.SubjectId
)
select studentid, subjectid, absenceid, count(*) as cnt
from (select cs.studentid, cs.subjectid,
(cs.ClassSeqNum - a.AbsentSeqNum) as absenceid
from cs join
a
on cs.studentid = a.studentid and cs.subjectid = as.subjectid
) a
group by studentid, subjectid, absenceid
having count(*) > 2