Join two group by commands into one - mysql

I have a table
________________________________________________________________________________
| Message |
|_______________________________________________________________________________|
| ID(INT) | Text(TEXT) |read(TINYINT(0/1)) |deleted(TINYINT(0/1))| User_id |
| 1 | How Are You?| 0 | 0 | 6 |
| 2 | Fine | 0 | 1 | 4 |
| 3 | Message 3 | 1 | 0 | 6 |
| 4 | Message 4 | 0 | 1 | 6 |
| 5 | Message 5 | 1 | 0 | 5 |
|_________|_____________|___________________|_____________________|_____________|
Now I want to select the message where user_id=6 and also select the column count for read=0 and read=1 seperately.I know this can be done by group by command and iam currently doing it with two sql queries .May somebody join them in one
select message,count(*) from message where User_id=6 and read=0 group by id;//for unread message
select message,count(*) from message where User_id=6 and read=1 group by id;//for read message

Joining your two queries is quite easy, but I don't get what you really want.
SELECT `message`, count(*) AS `cnt` , `read`
FROM message
WHERE `User_id`=6
AND `read` IN ( 0, 1 )
GROUP BY `id` , `read`;

Why don't you
select
message,
sum(read) as num_read,
sum(case read when 0 then 1 else 0 end) as num_unread
from message
where user_id = 6
group by user_id
? You can drop either the where or the group by line, depending on your real need and SQL implementation.

Try this:
select read,id,count(*)
from message
where user_id = 6 and read in (0,1) group by read,id

Related

MYSQL: how to return value from column that has relation to values in another column

Im struggling to articulate this, let alone execute in in MYSQL. How Do I return the userId X where userId.X and permissionId in (1,2,3,4,5,6,7,8) ?
The below example should return 6.
MariaDB [mailserver]> select * from user2permission;
+--------------+--------+
| permissionId | userId |
+--------------+--------+
| 1 | 5 |
| 1 | 6 |
| 2 | 6 |
| 2 | 7 |
| 3 | 6 |
| 4 | 6 |
| 5 | 6 |
| 6 | 6 |
| 7 | 6 |
| 8 | 6 |
+--------------+--------+
This kind of query can be written with the use of Group By clause and counting the instance as per the filteration applied in where clause
SELECT userId
FROM user2permission
WHERE permissionId IN (1,2,3,4,5,6,7,8)
GROUP BY userId
HAVING COUNT(*) = 8
You want to only show users that have an entry for all required permissions. Two solutions spring to mind:
select *
from users
where userid in (select userid from user2permission where permissionid = 1)
and userid in (select userid from user2permission where permissionid = 2)
...
and
select userid,
from user2permission
group by userid
having count(case when permissionid = 1 then 1 end) > 0
and count(case when permissionid = 2 then 1 end) > 0
...
And when I say "spring" to mind, I mean exactly that = without much thinking :-) Rizwan's aggregation solution is what you should use.

Joining and nesting queries in mysql

Currently, I'm using this nice query:
select
users.name,
sum(race_results.winnings) as total_winnings,
count(CASE WHEN race_results.place=1 THEN 1 ELSE 0 END) AS times_won_first_place
from users
inner join race_results
where race_results.userid = users.id and race_results.place = 1
group by users.id
order by total_winnings desc
to get this
************************************************
| name | total_winnings | times_won_first_place |
| Bob | 4000 | 4 |
| John | 1000 | 1 |
************************************************
the race_results table looks like this
*******************************************
| id | raceid | userid | place | winnings |
| 1 | 1 | 1 | 1 | 1000 |
| 2 | 1 | 2 | 5 | 50 |
| 3 | 1 | 3 | 6 | 50 |
| 4 | 2 | 1 | 1 | 1000 |
| 5 | 2 | 2 | 3 | 250 |
*******************************************
I would like to include four three more columns for something like this
***************************************************************************
| name | total_winnings | total_races | 1st_place | 2nd_place | 3rd_place |
| Bob | 4000 | 5 | 4 | 0 | 0 |
| John | 1000 | 5 | 1 | 1 | 1 |
***************************************************************************
If I were to do separate queries for the new columns, I'd use
select count(raceid) from race_results where userid = 1
select count(raceid) from race_results where userid = 1 and place = 1
select count(raceid) from race_results where userid = 1 and place = 2
select count(raceid) from race_results where userid = 1 and place = 3
to do separate queries would be easy but with the existing query I had to use CASE just to get the count of times a user won 1st place. (using
count(CASE WHEN race_results.place=2 THEN 1 ELSE 0 END)
returns the same results).
How would I nest these or join them into my existing query to get what I want?
You can do it this way:
select
users.name,
sum(race_results.winnings) as total_winnings,
count(*) AS total_races,
sum(race_results.place = 1) AS times_won_first_place ,
sum(race_results.place = 2) AS times_won_second_place,
sum(race_results.place = 3) AS times_won_third_place
from users
inner join race_results
where race_results.userid = users.id
group by users.id
order by total_winnings desc;
With ANSI standard SQL you could use case expressions inside the sum function but since MySQL (and some other databases) evaluate boolean expressions to 1 for true you can replace the case expression with the just the condition to evaluate and then just sum them.
So instead of CASE WHEN race_results.place=1 THEN 1 ELSE 0 END you can do sum(race_results.place=1) and save some space and typing :)
See this SQL Fiddle for an example.

Selecting multiple unrelated data from two tables and insert into one table mysql

This is my scenario
I have a permissions table with the following fields.
id | module | permission
1 | client | add
2 | client | edit
3 | client | delete
4 | someth | edit
5 | someth | delete
employee table
id | status | somestatus
1 | act | 1
2 | den | 1
3 | act | 0
4 | den | 1
5 | act | 0
6 | act | 1
Now what i would need to do is select the employee who have status="act" and somestatus=1 and give them all permissions where module="client"
so the table employee_permissions should have these rows
id | empid | permid | permvalue
1 | 1 | 1 | 1
2 | 1 | 2 | 1
3 | 1 | 3 | 1
1 | 6 | 1 | 1
2 | 6 | 2 | 1
3 | 6 | 3 | 1
This is the query I tried and I'm stuck here
INSERT INTO at2_permission_employee (employee_id,permission_id)
SELECT at2_employee.employee_id as employee_id
, (SELECT at2_permission.permission_id as permission_id
FROM at2_permission
where at2_permission.permission_module='client'
)
from at2_employee
where at2_employee.employee_status='Active'
and at2_employee.employees_served_admin = 1;
I get the error sub query returns multiple rows which makes sense to me. But I'm not sure how to modify the query to account for iterating over the rows returned by sub query
If I'm not wrong, like this:
INSERT INTO at2_permission_employee (employee_id, permission_id, permvalue)
SELECT
at2_employee.employee_id,
at2_permission.permission_id,
1
FROM at2_permission cross join at2_employee
WHERE
at2_employee.employee_status='Active'
and at2_employee.employees_served_admin = 1
and at2_permission.permission_module='client';
It's a bit unclear where the value for permvalue should come from so I hard coded it and used the permission.id for both id and permid, but this query should give you an idea on how to accomplish what you want:
insert employee_permissions (id, empid, permid, permvalue)
select p.id, e.id, p.id, 1
from employee e, permissions p
where p.module = 'client' and e.status = 'act' and e.somestatus = 1;

Count rows with specific value over multiple rows

Its very hard for to set a proper title, because I dont know how I describe my problem.
I have a table like this:
dlID | dl_seID | dlEpisode | dlFlag
___________________________________
1 | 1 | 1 | 0
2 | 1 | 2 | 1
3 | 1 | 3 | 1
4 | 2 | 1 | 1
5 | 2 | 2 | 0
6 | 3 | 1 | 0
What i want is a select query where I get something like this:
dlID | dl_seID | dlEpisode | dlFlag | dlFlagCount
_________________________________________________
1 | 1 | 1 | 0 | 2
2 | 1 | 2 | 1 | 2
3 | 1 | 3 | 1 | 2
4 | 2 | 1 | 1 | 1
5 | 2 | 2 | 0 | 1
6 | 3 | 1 | 0 | 0
dlFlagCount shoud be a counter of dlFlag = 1 where dl_seID = dl_seID.
Second try:
I need a value where I see how many Flags have the value 1 with the same dl_seID.
Is that possible?
I hope you guys know what I want^^
Regards
Try this:
select
a.*,
ifnull(b.ctflags,0)
from
tablea a left join
( select dl_seID, count(dlFlag) ctflags
from tablea
where dlFlag=1
group by dl_seID ) b on (a.dl_seID = b.dl_seID)
The left join is just to get the registry with 0 flags
See the fiddle: http://sqlfiddle.com/#!2/ef9b0/5
EDIT:
As op requested some explanation, here it goes:
What you asked is to count the amount of flags by the dl_seID and to do that you need to do this you separeta your problems, first you get the count for the dl_seID by flags, this is this subquery:
select dl_seID, count(dlFlag) ctflags
from tablea
where dlFlag=1
group by dl_seID
This became a 'separe table' or a new group of data, whatever you wanna call it. Then you have to join this with your original data (from your table) like the query for answer.
The left join part is because maybe there are some data that wont complain with where dlFlag=1 therefore if you want to get then as 0 you have to bring all values from table that exists or not on our created subgroup. And this ifnull(b.ctflags,0) is for theese data data exists on your table but has no flags (for your problem). If you use just b.ctflags it will bring null.
SELECT x.*
, COALESCE(y.flagcount,0) flagcount
FROM my_table x
LEFT
JOIN
( SELECT seID
, COUNT(*) flagcount
FROM my_table
WHERE flag = 1
GROUP
BY seid
) y
ON y.seid = x.seid;

Select rows who's FIRST result is a specific value

I've got a custom written analytics system running and I'm trying to write a query that returns users who landed on a specific page as their first hit. The relevant parts of the table is setup as such, with some simple data:
pageviews Table
+----+---------------------+----------+-------------+
| id | time_in | users_id | articles_id |
+----+---------------------+----------+-------------+
| 0 | 2013-08-15 00:00:00 | 0 | 0 |
| 1 | 2013-08-16 00:00:00 | 0 | 1 |
| 2 | 2013-08-17 00:00:00 | 1 | 1 |
| 3 | 2013-08-18 00:00:00 | 1 | 0 |
| 4 | 2013-08-19 00:00:00 | 1 | 1 |
| 5 | 2013-08-20 00:00:00 | 2 | 1 |
+----+---------------------+----------+-------------+
NOTE: The ID fields in my DB are actually using GUIDs, not ints as in this simple example.
Now, if I want to see who read article 1 as their first hit, I want my query to return users 1 and 2, but not 0, as user 0 saw article 0 as their first hit on the site. Conversely, if I want to see who read article 0 first, the query would only return user 0.
Here is my query thus far:
SELECT
*
FROM
pageviews
WHERE
articles_id = 1
GROUP BY
users_id
ORDER BY
time_in
But this returns distinct user IDs for all users who've read article 1, not filtering out the users who did not see it as their first result. I feel like I'm going the wrong direction with my query, so I'm turning towards you guys.
Thanks in advance.
One way to do it
SELECT v.users_id
FROM pageviews v JOIN
(
SELECT users_id, MIN(time_in) time_in
FROM pageviews
GROUP BY users_id
) q ON v.users_id = q.users_id AND v.time_in = q.time_in
WHERE v.articles_id = 1
Output:
| USERS_ID |
------------
| 1 |
| 2 |
Here is SQLFiddle demo
Another way:
SELECT users_id
FROM pageviews p
WHERE articles_id = 1
AND time_in = (SELECT MIN(time_in) from pageviews p2 WHERE p2.users_id = p.users_id)
SQLFiddle here