in barcodes table i have two column witch they are enter, exit like with student attendance record,
in this table when student entered to class, i add new row in table and enter value is 1 and exit is 0 like with login
after exiting from classroom i check latest row of this student and if enter is 1 then i add new row in table with 1 value for exit like with logout
now i want to calculate counting all students witch enter column is 1 and exit value is 0 to get all present students in class
SAMPLE DATA:
in this DB-FIDDLE i have sample data and into that i have 2 present student that session_id of them is 1, they are 123451,123452 students, but my sql command as second part is incorrect and that return one present student:
(
select count(*)
from barcodes b
where b.session_id = s.id
group by session_id, barcode
having sum(exit) = 0
) as present
for example:
select s.id, s.session_name, s.session_type, s.date_time,
(
select count(*)
from barcodes b where b.session_id = s.id
) as barcode_count ,
(
select count(*)
from barcodes b
where b.session_id = s.id
group by session_id, barcode
having sum(exit) = 0
) as present
from sessions s;
If I get what you want to do right, you can add another, outer aggregation.
...
(SELECT sum(x.count)
FROM (SELECT count(*) count
FROM barcodes b
WHERE b.session_id = s.id
GROUP BY b.session_id,
b.barcode
HAVING sum(b.enter) <> 0
AND sum(b.exit) = 0) x) present
...
But I think there's a much simpler way to get what you want by just taking the sum of enter minus exit for the session. Since any row with exit = 1 also comes with enter = 1, we need to double the exit before subtraction though.
...
(SELECT sum(b.enter - 2 * b.exit)
FROM barcodes b
WHERE b.session_id = s.id) present
...
If you can trust the data, something like this could work:
select
s.id,
s.session_name,
s.session_type,
s.date_time,
count(*) as barcode_count,
sum(exit = 0) - sum(exit = 1) as present
from sessions s
left join barcodes b on b.session_id = s.id
group by s.id, s.session_name, s.session_type, s.date_time
db-fiddle
You can read sum(exit = 0) - sum(exit = 1) as (number of entries) - (number of exits). If 4 students entered a class and 2 left the class, I would expect 2 students (4 - 2) to be still in the class.
Related
I have two tables, tasks and views, with the following structure:
tasks
-- id
-- status
views
-- id
-- taskid (FK of tasks.id)
-- status
And the tasks table, has a row with id = 1 and status = 1, whilst the views table has two rows with id = 1, taskid = 1, status = 1 and id = 2, taskid = 1, status = 0.
When I try to get all the tasks id that have all its views status set to 1 and the task's status itself set to 1 too and only, then I get in return a row with task id = 1 because view number 1 is set to 1 and view number 2 is set to 0.
So basically, what I need is an SQL statement that returns only one row for each task that has all its views and task status set to 1 (tasks.status = 1, views.status = 1) and only when that happens, and if any of the tasks' views is set to something different than 1, then the SQL statement doesn't return it.
Here is my SQL Statement so far which kind of works, but there is still something I am missing because it doesn't work as expected. Sorry if something isn't clear!
SELECT tasks.id FROM tasks JOIN views ON tasks.id = views.taskid WHERE tasks.status = 1 AND views.status = 1;
Join tasks to a query that uses aggregation to return only the taskids with min status set to 1 (which means there is no 0):
SELECT t.id
FROM tasks t
INNER JOIN (
SELECT taskid
FROM views
GROUP BY taskid
HAVING MIN(status) = 1
) v ON v.taskid = t.id
WHERE t.status = 1;
with t as (select taskid,
count(status) status_cnt,
sum(case when status = 1 then 1 else 0 end) as status_1_cnt
from views
group by taskid),
t2 as (select taskid from t where status_1_cnt > 0 and status_cnt = status_1_cnt)
select tasks.id from tasks join t2 on tasks.id = t2.taskid and status = 1
so If I am reading your question correctly you want all of the statuses in the view to be 1 per taskid. so I would count the view statuses and compare that count to where the view status is 1. (the case statement).
then just join this to the task table where the task status is 1
(although I like #forpas answer better)
Conceptually you only want to join on the records in the views table where status = 1, so like this:
SELECT A.id
FROM
tasks A
INNER JOIN
(
SELECT
tasks.taskid
FROM
views
WHERE
view.status = 1
) B
ON A.id = B.taskid
Although the syntax is less intuitive, this is equivalent and shorter:
SELECT
tasks.id
FROM
tasks
JOIN views
ON tasks.id = views.taskid
AND view.status = 1
WHERE
tasks.status = 1
This should also work, for a different reason (more like a trick):
SELECT A.id
FROM
tasks A
INNER JOIN views B
ON a.id = b.taskid
and a.status = b.status
WHERE
A.status = 1
This might be more stringent of a test if thats what you need (the matching records in views with the requirement that no other records with status = 0 exist in views) - but I would like to avoid this style of using a correlated subquery in real life if the tables are of an significant size:
SELECT A.id
FROM
tasks A
INNER JOIN views B
ON A.id = B.taskid
WHERE
A.status = 1
AND B.status = 1
AND NOT EXISTS (SELECT * FROM views c
WHERE c.taskid = b.taskid and c.status = 0)
Finally this is a solution that thinks conceptually more in terms of the intersection of the sets:
SELECT A.id
FROM
tasks a
INNER JOIN views a
ON A.id = b.taskid
AND b.status = 1
LEFT JOIN views c
ON a.id = c.taskid
AND c.status = 0
WHERE
A.status = 1
AND c.status is null
I just saw that forpas has just shown a different but very good solution using aggregation with a min() clause to select only the appropriate records from views for use in joining to tasks which seems like it may be the winner to me :)
If I understand you correctly, you want to get id of task , if and ONLY if it's status = 1, and there are particular records in views table with ONLY same status = 1.
Then your query would be like this:
select tasks.id
from tasks
where status =1 and not exists(
select 1
from views
where taskid=tasks.id and views.status!=tasks.status)
Check demo https://www.db-fiddle.com/f/cQfQMx5LGJN516ND2iVj8y/3
I am using the following query to retrieve the number of events per state from 2 tables that are linked by a userID.
SELECT state,COUNT(*) AS num
FROM tableUserInfo
WHERE userID IN (SELECT userID
FROM tableEvents
WHERE conditionOne = 1
AND conditionTwo = 2)
GROUP BY state
This query works correctly. My problem is that not all states have user entries, and I need the query to return 0 for those. I was wondering if there was a method such as joining or using an in clause, that would included a set of all states, making the query return 0 for any that didn't have entries in tableEvents?
Do you have a list of states? If not then this would give a list of all the states your database knows about:
SELECT DISTINCT state FROM tableUserInfo
....and enclosing this in brackets it can be dropped in place in the query below:
SELECT s.state, IFNULL(cnt, 0) AS num
FROM list_of_states s
LEFT JOIN (
SELECT state,COUNT(*) AS cnt
FROM tableUserInfo ui
INNER JOIN tableEvents te
ON ui.userId=te.userId
WHERE conditionOne = 1
AND conditionTwo = 2
GROUP BY state
) u
ON s.state=u.state;
Although in the absence of "list_of_states" it would be more efficient to do this:
SELECT ui.state, SUM(IF(te.userId IS NULL, 0, 1)) AS cnt
FROM tableUserInfo ui
LEFT JOIN tableEvents te
ON ui.userId=te.userId
AND te.conditionOne = 1
AND te.conditionTwo = 2
GROUP BY state;
As #raymond-nijland suggested you can use Left Join to include all states.
SELECT tableUserInfo.state,COUNT(tableUserInfo.*) AS num
FROM tableUserInfo Left Join tableEvents on tableUserInfo.userID = tableEvents.userID
WHERE tableEvents.conditionOne = 1 AND tableEvents.conditionTwo = 2
GROUP BY state
Have tables: person,person_ip
Both tables have pid column as a primary key, in table person there is column state_id, in table person_ip there is column ip.
Want to discover if specified IP address is assigned to person with state_id is not equal to 2. But always got result 1, even if state_id is 0, 1 or 2. Always got 0 only if ip address is not listed at all. What am I doing wrong?
SELECT EXISTS (
SELECT person_ip.PID
FROM person_ip,person
WHERE person.PID=person_ip.PID
AND person.state_id NOT IN (2)
AND person_ip.ip='10.11.12.13'
)
this seems like a simple join.. unless i'm missing something
select person.*
from person
inner join person_ip
on person.pid = person_ip.pid
where person.state_id <> 2
and person_ip.ip_address = '10.0.0.1'
If you want to exclude the ip_address if it has been assigned to any user with state = 2, even if it has also been assigned to a user without state = 2, then try:
select max(i)
from (
select *
from (
select 1 as i
from dual
where not exists (
select 1
from person p
inner join person_ip pi
on p.pid = pi.pid
where p.state_id = 2
and pi.ip_address = '10.0.0.1'
)
) q
union
select 0
) qq
(dual is a system table that can be used as a sort of stub table)
here's a fiddle showing both versions
update after some actual sleep
Okay, so the above query is a little.. out there. Back in the real world, this one is probably more appropriate:
select count(case when p1.state_id = 2 then 1 end)
from person p1
inner join person_ip pi1
on p1.pid = pi1.pid
where pi1.ip_address = '10.0.0.1'
group by pi1.ip_address;
This will return 1 or more if your ip_address has been used by someone with a state_id of 2, and 0 if it has never been used by someone with a state_id of 2.
It will return nothing if the ip has never been used.
this fiddle has all three of the above queries.
SELECT IF(COUNT(*)>0,1,0)
FROM person
INNER JOIN person_ip
ON person.pid = person_ip.pid
AND person_ip.ip_address = '10.0.0.1'
WHERE person.state_id <> 2
i am trying to write the Query for three things .My table structure is like that
You can see Schema at http://sqlfiddle.com/#!2/56c2d/1
I am trying to write the query in MYSQL
user:- table
user_id
user_fname
This is User tabke which will save User Information
group:- "group" and "subgroup" is maintain in same table using column "group_parent_group_id"
group_id
group_title
group_parent_group_id(INT)
This is group table which will save Group and Subgroups
user_group: table
user_group_id
user_group_user_id
user_group_group_id
This ill store both User and Group relation using their Id
I am trying to write the Query for three things. Fetching Users Groups, Subgroups
1) Query to fetch list of All Groups for User Register. Query is gelow and is giving error
Query:
select user.id, user.user_fname, group.group_id, group.group_title
from `user`
inner join user_group on user_group.user_group_user_id = user.user_id
inner join group on group.group_id = user_group.user_group_group_id
where user_group.user_group_user_id = 1 and user_group.group_parent_group_id = 0
2) I am Looking the query to fetch all subgroups(For Whom user is already Register) for Group Id 1,2 or 1
3) I am Looking the query to fetch all subgroups(For Whom user is Not Register yet) for Group Id 1,2 or 1. Ideal is for giving him randomly suggest a subgroup to add
Please Help. I am a newbie in DB :(
Your query is probably failing as you have a table called group, which is a reserved word. You can use back tics to delimit the name to get away with this (as follows) but it would be a better idea to change the table name.
SELECT user.id, user.user_fname, `group`.group_id, `group`.group_title
FROM `user`
INNER JOIN user_group ON user_group.user_group_user_id = user.user_id
INNER JOIN `group` ON `group`.group_id = user_group.user_group_group_id
WHERE user_group.user_group_user_id = 1
AND user_group.group_parent_group_id = 0
EDIT updated for queries I think the OP requires.
First query will get a list of all the groups (ones that have no parent group id) that a user (in this case id 28) is a member of
SELECT y2m_user.user_id, y2m_user.user_first_name, y2m_group.group_id, y2m_group.group_title
FROM y2m_user
INNER JOIN y2m_user_group ON y2m_user_group.user_group_user_id = y2m_user.user_id
INNER JOIN y2m_group ON y2m_group.group_id = y2m_user_group.user_group_group_id
WHERE y2m_user.user_id = 28
AND y2m_group.group_parent_group_id = 0
This query will get a list of all the sub groups (ones where the parent group id is greater than 0) that a user (in this case id 28) is a member of
SELECT y2m_user.user_id, y2m_user.user_first_name, y2m_group.group_id, y2m_group.group_title
FROM y2m_user
INNER JOIN y2m_user_group ON y2m_user_group.user_group_user_id = y2m_user.user_id
INNER JOIN y2m_group ON y2m_group.group_id = y2m_user_group.user_group_group_id
WHERE y2m_user.user_id = 28
AND y2m_group.group_parent_group_id > 0
This query will get a list of all the sub groups (ones where the parent group id is greater than 0) that a user (in this case id 28) is NOT a member of
SELECT y2m_user.user_id, y2m_user.user_first_name, y2m_group.group_id, y2m_group.group_title
FROM y2m_user
CROSS JOIN y2m_group
LEFT OUTER JOIN y2m_user_group ON y2m_user_group.user_group_user_id = y2m_user.user_id AND y2m_group.group_id = y2m_user_group.user_group_group_id
WHERE y2m_user.user_id = 28
AND y2m_group.group_parent_group_id > 0
AND y2m_user_group.user_group_id IS NULL
Please excuse any typos as not tested (with your test data there are no sub groups).
i have a details table with columns:
user_id int
code int
value int
And i want to build a summary table that looks like:
user_id int
valueA int
valueB int
In the details table, valueA would correspond to say, code 5, and valueB would correspond to say, code 6, so i'm looking for something like:
insert into summary (user_id,valueA,valueB) VALUES ( SELECT ??? from details );
The problem of course is that i'm looking at multiple rows from the "details" table to populate one row in the "summary" table.
Eg, if i had the following rows in details:
1 5 100
1 6 200
2 5 1000
2 6 2000
I want to end up with the following in the summary table:
1 100 200
2 1000 2000
Any ideas?
MySQL doesn't have PIVOT/UNPIVOT syntax, which leaves you to use a combination of GROUP BY and CASE expressions:
INSERT INTO SUMMARY
(user_id,valueA,valueB)
SELECT d.user_id,
MAX(CASE WHEN d.code = 5 THEN d.value ELSE NULL END),
MAX(CASE WHEN d.code = 6 THEN d.value ELSE NULL END),
FROM DETAILS d
GROUP BY d.user_id
insert into summary (user_id,valueA,valueB)
SELECT a.user_id, a.value, b.value
from details a
join details b on a.user_id = b.user_id
WHERE a.code = 5 and b.code = 6;
beware: you will end up with multiple summary columns if user_id+code is not unique.
EDIT:
insert into summary (user_id,valueA,valueB)
select u.user_id, ifnull(a.value,0), ifnull(b.value,0)
from (select distinct user_id from details /* where code in (5,6) */) u
left join details a on a.user_id = u.user_id and a.code = 5
left join details b on b.user_id = u.user_id and b.code = 6
If you have a manageable set of codes (say just 5 and 6) you could do something like this:
SELECT details.user_id, code5.value, code6.value
FROM details JOIN
(SELECT user_id, value FROM details WHERE code = 5) AS code5 USING(user_id)
JOIN
(SELECT user_id, value FROM details WHERE code = 6) AS code6 USING(user_id);
You may need to modify your JOINs depending on if your codes are not required as 1 to 1 relationship (i.e. LEFT JOINs).
If you have a large set of codes, I would look into a cursor runs a similar query above over a result set of your codes or using a different technology, (i.e. PHP script).