See the attached image to see the data I have.
I am trying to get a result like this:
SessionNumber | Event Date| Critical Care Count | Pulmonary Circulation
G1 | 5/19/2018 | 2 | 3
G1 | 5/20/2018 | 5 | 1
PCC1 | 5/19/2018 | 4 | 5
I'm trying to count the various primaryAssembly, topic, reg per SessionNumber and EventDate.
This is the query I am using:
select SessionNumber, EventDate, count(distinct BadgeID) as CriticalCareCount
from beacon
where primaryAssembly="Critical Care"
group by SessionNumber, EventDate
order by EventDate;
But I would rather not have to use the 'Where' clause. I'd like grouping on the term itself.
Here's a screen shot:
A pivot query can help:
SELECT SessionNumber,Event_Date,
count( case when primaryAssembly = 'Critical Care' then 1 end )
As Critical_Care_Count,
count( case when primaryAssembly = 'Pulmonary Circulation' then 1 end )
As Pulmonary_Circulation_Count,
count( case when primaryAssembly = 'Some other value' then 1 end )
As Some_other_value_Count,
......
......
count( case when some_other_logical_condition then 1 end )
As some_other_condition_count
......
......
SUM( case when primaryAssembly = 'Critical Care' then Duration else 0 end )
As sum_of_duration_for_critical_care
......
......
count(*) As total_count
FROM table
GROUP BY SessionNumber,Event_Date
Related
Here is my MySQL query with its result, I want to obtain for each value of 'function' the first result of 'priority', and thus get the result below
However, a syntax of the type "SELECT function, FIRST (priority) ... GROUP BY function" does not exist, do you have any idea how to do this?
SELECT
function,
priority
FROM challenge_access_rule
WHERE 10 = challenge_access_rule.challenge_id
AND (
rule = 'everybody'
OR (rule = 'friends' AND 1)
)
UNION
SELECT
function,
isRestriction AS priority
FROM challenge_access_user
WHERE 10 = challenge_access_user.challenge_id AND challenge_access_user.user_id = 2
ORDER BY ABS(priority)
-- RESULT --
emitInstance | 0
emitDeal | 0
emitDealInstance | 1
emitDeal | 100
emitDealInstance | -100
vote | -100
emitDeal | -200
view | -200
interact | -200
-- DESIRED RESULT --
emitInstance | 0
emitDeal | 0
emitDealInstance | 1
vote | -100
view | -200
interact | -200
Thanks,
Bastien
First, I would simplify your current query to:
SELECT car.function, car.priority
FROM challenge_access_rule car
WHERE 10 = car.challenge_id AND
( car.rule in ('everybody', 'friends') or
car.user_id = 2
)
ORDER BY ABS(car.priority);
Then, if you want the minimum of the absolute value of the priority, then you can use aggregation and a substring_index()/group_concat() trick:
SELECT car.function,
substring_index(group_concat(car.priority order by ABS(car.priority)), ',', 1) as priority
FROM challenge_access_rule car
WHERE 10 = car.challenge_id AND
( car.rule in ('everybody', 'friends') or
car.user_id = 2
)
GROUP BY car.function;
or a case expression:
SELECT car.function,
(case when min(car.priority) = - min(abs(car.priority))
then - min(abs(car.priority))
else min(car.priority)
end) as priority
FROM challenge_access_rule car
WHERE 10 = car.challenge_id AND
( car.rule in ('everybody', 'friends') or
car.user_id = 2
)
GROUP BY car.function;
This code work !
Thanks to Gordon
SELECT function,
substring_index(group_concat(priority ORDER BY ABS(priority)), ',', 1)
FROM (
SELECT
function,
priority
FROM challenge_access_rule
WHERE 10 = challenge_access_rule.challenge_id
AND (
rule = 'everybody'
OR (rule = 'friends' AND 1) -- 'AND 1' edit after
)
UNION
SELECT
function,
isRestriction AS priority
FROM challenge_access_user
WHERE 10 = challenge_access_user.challenge_id AND challenge_access_user.user_id = 2
ORDER BY ABS(priority)
) AS toto
GROUP BY function
Consider:
SELECT(count(c.id),
case when(count(c.id) = 0)
then 'loser'
when(count(c.id) BETWEEN 1 AND 4)
then 'almostaloser'
when(count(c.id) >= 5)
then 'notaloser'
end as status,
...
When all is said and done, the query as a whole produces a set of results that look similar to this:
Count | status
--------|-------------
2 | almostaloser //total count is between 2 and 4
--------|-------------
0 | loser // loser because total count = 0
--------|-------------
3 | almostaloser //again, total count between 2 and 4
--------|-------------
What I would like to achieve:
a method to reatain the information from the above table, but add a third column that will give a total count of each status, something like
select count(c.id)
case when(count(c.id) = 0 )
then loser as status AND count how many of the total count does this apply to
results would look similar to:
Count | status |total_of each status |
--------|-------------|---------------------|
2 | almostaloser| 2 |
--------|-------------|---------------------|
0 | loser | 1 |
--------|-------------|---------------------|
3 | almostaloser| 2 |
--------|-------------|----------------------
I've been told this could be achieved using a derived table, but i've not yet been able to get them both, only one or the other.
This can be achieved with this query (you must place your original query as subquery in two places):
SELECT t1.*, t2.total_of_each_status
FROM (
-- put here your query --
) t1
INNER JOIN (
SELECT status, count(*) AS total_of_each_status
FROM (
-- put here your query --
) t2
GROUP BY status
) t2 ON t2.status = t1.status
I have a table like this :
Type | Time
1 | 234234
2 | 234235
1 | 234238
3 | 234239
4 | 234240
1 | 234242
2 | 234245
I want to count number of all those rows where type=1 and next row's type=2.
For ex : The result here is 2.
I don't know how to put where clause on next row.
You should be able to implement user defined variables to get the total:
select count(*) Total
from
(
select type,
#row:=(case when #prev=1 and type=2 then 'Y' else 'N' end) as Seq,
#prev:=type
from yourtable, (SELECT #row:=null, #prev:=null) r
order by time, type
) src
where Seq = 'Y'
See SQL Fiddle with Demo
I have a table called user_scores as below:
id | af_id | uid | level | record_date
----------------------------------------
1 | 1.1 | 1 | 3 | 2012-01-01
2 | 1.1 | 1 | 4 | 2012-02-01
3 | 1.2 | 1 | 3 | 2012-01-01
4 | 1.2 | 1 | 5 | 2012-03-01
...
I have another table call user_info as below:
uid | forename | surname | gender
-----------------------------------
1 | Homer | Simpson | M
2 | Marge | Simpson | F
3 | Bart | Simpson | M
4 | Lisa | Simpson | F
...
In user scores uid is the user id of a registered user on the system, af_id identifies a particular test a user submits. A user scores a level between 1 - 5 for each test, which can be submitted every month.
My problem is I need to produce an analysis at the end of the year to COUNT the number of users that have achieved each level for a particular test. The analysis is to show a gender split for male and female.
So for example an administrator would select test 1.1 and the system would generate stats based that would COUNT of the total MAX level achieved by each user in the year, with a gender split.
Any help is much appreciated. Thank you in advance.
-
I think I need to clarify myself a bit. Because a user can complete the test multiple times throughout the year, there will be multiple scores for the same test. The query should take the highest level achieved and include this in the count. An example result would be:
Male Results:
level1 | level2 | level3 | level4 | level5
------------------------------------------
2 | 5 | 10 | 8 | 1
I am not certain I get exactly what you mean, but as always I'll have a go. As I understand it you want to know how many people from each gender reached each level in a certain year.
SELECT MaxLevel,
COUNT(CASE WHEN ui.Gender = 'M' THEN 1 END) AS Males,
COUNT(CASE WHEN ui.Gender = 'F' THEN 1 END) AS Females
FROM User_Info ui
INNER JOIN
( SELECT MAX(Level) AS MaxLevel,
UID
FROM User_Scores us
WHERE af_ID = '1.1'
AND YEAR(Record_Date) = 2012
GROUP BY UID
) AS MaxUs
ON MaxUs.uid = ui.UID
GROUP BY MaxLevel
I've put some sample data on SQL Fiddle so you see if it is what you were after.
EDIT
To transpose the data so levels are along the top and Gender in the rows the following will work:
SELECT Gender,
COUNT(CASE WHEN MaxLevel = 1 THEN 1 END) AS Level1,
COUNT(CASE WHEN MaxLevel = 2 THEN 1 END) AS Level2,
COUNT(CASE WHEN MaxLevel = 3 THEN 1 END) AS Level3,
COUNT(CASE WHEN MaxLevel = 4 THEN 1 END) AS Level4,
COUNT(CASE WHEN MaxLevel = 5 THEN 1 END) AS Level5
FROM User_Info ui
INNER JOIN
( SELECT MAX(Level) AS MaxLevel,
UID
FROM User_Scores us
WHERE af_ID = '1.1'
AND YEAR(Record_Date) = 2012
GROUP BY UID
) AS MaxUs
ON MaxUs.uid = ui.UID
GROUP BY Gender
Note, that if there are ever more than 5 levels you will need to add more to the select statement, or start building dynamic SQL.
Assuming record_date holds only dates (without time parts):
SELECT
s.maxlevel,
COUNT(NULLIF(gender, 'F')) AS M,
COUNT(NULLIF(gender, 'M')) AS F
FROM user_info u
INNER JOIN (
SELECT
uid,
MAX(level) AS maxlevel
FROM user_scores
WHERE record_date > DATE_SUB(CURDATE(), INTERVAL DAYOFYEAR(CURDATE()) DAY)
AND af_id = '1.1'
GROUP BY
uid
) s ON s.uid = u.uid
GROUP BY
s.maxlevel
That will show you only the maximum levels found in the user_scores table. If you have a Levels table where all possible levels (1 to 5) are listed, you could use that table to get a complete list of levels. If some levels are not present in the requested subset of data, the corresponding rows will show 0s in both columns.
Here's the above script with minor changes to show the complete chart of levels:
SELECT
l.level AS maxlevel,
COUNT(NULLIF(gender, 'F')) AS M,
COUNT(NULLIF(gender, 'M')) AS F
FROM user_info u
INNER JOIN (
SELECT
uid, MAX(level) AS maxlevel
FROM user_scores
WHERE record_date > DATE_SUB(CURDATE(), INTERVAL DAYOFYEAR(CURDATE()) DAY)
AND af_id = '1.1'
GROUP BY
uid
) s ON s.uid = u.uid
RIGHT JOIN Levels l ON s.maxlevel = l.level
GROUP BY
l.level
Hope this is what your looking for!
Show number of records group by userid and gender of the max score for af_id '1.1'.
select count(*), info.uid, info.gender, max(score.level)
from user_info as info
join user_scores as score
on info.uid = score.uid
where score.af_id = '1.1'
group by info.uid, info.gender;
EDITED based on your edit.
select sum(if(a.gender="M",1,0)) Male_users, sum(if(a.gender="F",1,0)) Female_users
from myTable a where
a.level = (select max(b.level) from myTable b where a.uid=b.uid)
group by af_id.
I typed this in a rush. But it should work or at least get you where you need to go. E.G. if you need to specify time frame, add that.
You need something like
SELECT
uid,
MAX(level)
WHERE
record_date BETWEEN '2012-01-01' AND '2012-12-31'
AND af_id='1.1'
GROUP BY uid
If you need the gender splits then depending on what stat you need per gender you can either add a JOIN on the user_info table into this query (to get the MAX per gender) to wrap this as a sub-query and JOIN on the whole thing.
i have the following table Students:
id | status | school | name
----------------------------
0 | fail | skool1 | dan
1 | fail | skool1 | steve
2 | pass | skool2 | joe
3 | fail | skool2 | aaron
i want a result that gives me
school | fail | pass
---------------------
skool1 | 2 | 0
skool2 | 1 | 1
I have this but it's slow,
SELECT s.school, (
SELECT COUNT( * )
FROM school
WHERE name = s.name
AND status = 'fail'
) AS fail, (
SELECT COUNT( * )
FROM school
WHERE name = s.name
AND status = 'pass'
) AS pass,
FROM Students s
GROUP BY s.school
suggestions?
Something like this should work:
SELECT
school,
SUM(CASE WHEN status = 'fail' THEN 1 ELSE 0 END) as [fail],
SUM(CASE WHEN status = 'pass' THEN 1 ELSE 0 END) as [pass]
FROM Students
GROUP BY school
ORDER BY school
EDIT
Almost forgot, but you could also write the query this way:
SELECT
school,
COUNT(CASE WHEN status = 'fail' THEN 1 END) as [fail],
COUNT(CASE WHEN status = 'pass' THEN 1 END) as [pass]
FROM Students
GROUP BY school
ORDER BY school
I'm not sure if there's any performance benefit with second query. My guess would be if there is it's probably very small. I tend to use the first query because I think it's more clear but both should work. Also, I don't have a MySql instance handy to test with, but according to #Johan the ORDER BY clauses are unnecessary.
SELECT q.school, q.fail, q.failpass-q.fail as pass
FROM
(
SELECT s.school, sum(if(status = 'fail',1,0)) as fail, count(*) as failpass
FROM students s
GROUP BY s.school
) q
This way you save one conditional sum.
In MySQL a GROUP BY already orders the results, so a separate ORDER BY is not needed.