mysql group by select with conditional value - php

In my messages table I have following rows for example,
|----|---------|--------------|------|
| id | user_id | message |status|
|====|=========|==============|======|
| 1 | 2 | msgs 11 | r |
|----|---------|--------------|------|
| 2 | 3 | msgs 12 | r |
|----|---------|--------------|------|
| 3 | 2 | msgs 13 | r |
|----|---------|--------------|------|
| 4 | 3 | msgs 14 | u |
|----|---------|--------------|------|
Now, I need to know two things for each user_id
Whether it has any status u or not.
How many messages are there
For example, a query like below
select user_id, status, count(*) as totalMsg from messages group by user_id
Would brought me following rows
| user_id | status| totalMsg |
|=========|=======|==========|
| 2 | r | 2 |
|---------|-------|----------|
| 3 | r | 2 |
^
|------> I need this value to be 'u' because user 3 has a message u
My current query doesnt really gurantee that it will look for a u in the status column.
Is that possible to do? If so how?

MAX() will work on this since r is the least value based on the lexicographical order.
SELECT user_ID,
MAX(status) status,
COUNT(*) totalMsg
FROM messages
GROUP BY user_ID

Related

Select all fields from a table where a field in another table with an ID is equal to a string

I have 2 tables:
Ads: Fields ID, A, B and C:
+----+---+-------+------+
| ID | A | B | C |
+----+---+-------+------+
| 1 | x | y | z |
| 2 | c | v | b |
| 3 | n | n | m |
+----+---+-------+------+
Requests: Fields ID, AdID, and Status:
+----+------+----------+
| ID | AdID | Status |
+----+------+----------+
| 3 | 1 | pending |
| 4 | 2 | approved |
| 5 | 3 | pending |
+----+------+----------+
ID (from Ads) = AdID (from Requests).
Now, I want to get all records from Ads where AdID's (from Requests) Status equals pending. AdId here would be the value ID from Ads.
So, with the above tables, the result I'd get would be ID 1 and 3 from Ads:
+----+---+---+---+
| ID | A | B | C |
+----+---+---+---+
| 1 | x | y | z |
| 3 | n | n | m |
+----+---+---+---+
This is the closest I've got so far, but this obviously doesn't work because it can only select one row - whereas I need to select many:
SELECT * FROM Ads WHERE ID = (SELECT AdID FROM Requests WHERE Status = 'pending')
This might not make sense - please ask if I haven't explained it well - I'll help as much as possible :)
Use IN in place of =:
SELECT *
FROM Ads
WHERE ID IN (SELECT AdID FROM Requests WHERE Status = 'pending')
Try this:
SELECT * FROM Ads A LEFT JOIN Requests R ON A.ID=R.AdID WHERE R.AdID='pending';

SQL: get data spread over 3 tables

I am trying to get some statistics for an online game I maintain. I am searching for an SQL statement to get the result on the bottom.
There are three tables:
A table with teams, each having a unique identifier.
table teams
---------------------
| teamid | teamname |
|--------|----------|
| 1 | team_a |
| 2 | team_x |
---------------------
A table with players, each having a unique identifier and optionally an affiliation to one team by it's unique teamid.
table players
--------------------------------
| playerid | teamid | username |
|----------|--------|----------|
| 1 | 1 | user_a |
| 2 | | user_b |
| 3 | 2 | user_c |
| 4 | 2 | user_d |
| 5 | 1 | user_e |
--------------------------------
Finally a table with events. The event (duration in seconds) is related to one of the players through their playerid.
table events.
-----------------------
| playerid | duration |
|----------|----------|
| 1 | 2 |
| 2 | 5 |
| 3 | 3 |
| 4 | 8 |
| 5 | 12 |
| 3 | 4 |
-----------------------
I am trying to get a result where the durations of all team members is summed up.
result
--------------------------
| teamid | SUM(duration) |
|--------|---------------|
| 1 | 14 | (2+12)
| 2 | 15 | (3+8+4)
--------------------------
I tried several combinations of UNION, WHERE IN, JOIN and GROUP but could not get it right. I am using PostgreSQL and PHP. Can anyone help me?
Just use sum with group by:
select t.teamid, sum(e.duration)
from team t
join players p on t.teamid = p.teamid
join events e on p.playerid = e.playerid
group by t.teamid
If you need all teams to be returned even if they don't have events, then use an outer join instead.
Try this
SELECT teamid, Sum(duration),
AS LineItemAmount, AccountDescription
FROM teams
JOIN teams ON teams.teamid = players.teamid
JOIN events ON players.playersid = events.playersid
JOIN GLAccounts ON InvoiceLineItems.AccountNo = GLAccounts.AccountNo
GROUP BY teamid
http://www.w3computing.com/sqlserver/inner-joins-join-two-tables/

MySQL Sum multiple column values with conditions

I have the following schema (two tables):
**APPS**
| ID (bigint) | USERID (Bigint) | USAGE_START_TIME (datetime) |
------------------------------------------------------------------
| 1 | 12 | 2013-05-03 04:42:55 |
| 2 | 12 | 2013-05-12 06:22:45 |
| 3 | 12 | 2013-06-12 08:44:24 |
| 4 | 12 | 2013-06-24 04:20:56 |
| 5 | 13 | 2013-06-26 08:20:26 |
| 6 | 13 | 2013-09-12 05:48:27 |
**USAGE**
| ID (bigint) | APPID (bigint) | DEVICEID (bigint) | HIGH_COUNT (bigint) | MEDIUM_COUNT (bigint) |
--------------------------------------------------------------------------------------------------------
| 1 | 1 | 2 | 400 | 200 |
| 2 | 1 | 3 | 200 | 100 |
| 3 | 2 | 3 | 350 | 40 |
| 4 | 3 | 4 | 2 | 400 |
| 5 | 4 | 2 | 4 | 30 |
| 6 | 5 | 3 | 50 | 300 |
Explanation:
So, there are two tables.
Now I want to find the following:
Given a USERID, Get sum of HIGH_COUNT & MEDIUM_COUNT. While counting
the SUM it should be taken care that: If in USAGE, same device is used
more than once, then the record which has the latest info (based on
APPS.USAGE_START_TIME), should be considered while calculating the
sum.
For ex:
For above schema, result should be (for userid=12) :
| HIGH_COUNT (bigint) | MEDIUM_COUNT (Bigint) |
-----------------------------------------------
| 356 | 470 |
SQL Fiddle: http://sqlfiddle.com/#!2/74ae0f
If a user uses multiple APPS on one device, this query will use the APPS row with the highest usage_start_time:
select a.userid
, sum(u.high_count)
, sum(u.medium_count)
from apps a
join `usage` u
on u.appid = a.id
join (
select u.device_id
, a.userid
, max(a.usage_start_time) as max_start_time
from apps a
join `usage` u
on u.appid = a.id
group by
u.device_id
, a.userid
) filter
on filter.device_id = u.device_id
and filter.userid = a.userid
and filter.max_start_time = a.usage_start_time
group by
a.userid
In your dataset, it will select usage rows 5, 3, 4 for user 12.
See it working at SQL Fiddle.
I can't quite get your numbers, but something like this should work...
SELECT a.userid
, SUM(u.high_count)
, SUM(u.medium_count)
FROM apps a
JOIN `usage` u
ON u.appid = a.id
JOIN
( SELECT userid
, deviceid
, MAX(usage_start_time) max_usage_start_time
FROM apps a
JOIN `usage` u
ON u.appid = a.id
GROUP
BY userid
, deviceid
) x
ON x.userid = a.userid
AND x.deviceid = u.deviceid
AND x.max_usage_start_time = a.usage_start_time
GROUP
BY userid;
Note that usage is a reserved word. Therefore, this is a bad name for a column (or a table). Also, note inconsistencies between your question and your fiddle.
I think not had chance to test it but
SELECT SUM(HIGH_COUNT), SUM(MEDIUM_COUNT) FROM `USAGE` INNER JOIN `APPS` ON USAGE.APPID=APPS.ID WHERE APPS.USERID=$input_user_id_to_lookup
will give you your counts.
For yoru other question (homework?) you didn't give us the full schema so we can't guess what you need doing.
Also whoever designed that db should be shot its horrible

Mysql query comma separator

I having two tables
table 1: users
| id | username |
| 1 | john |
| 2 | marry |
| 3 | deep |
| 4 | query |
| 5 | value|
and
table 2:users_2
| table_2_id | user_id |
| 1 | 2,4 |
I need required something like this
| table_2_id | username |
| 1 | marry,query |
anyone can help me for this output in mysql
Is this what you are looking ?
select
`users_2`.`table_2_id` , GROUP_CONCAT(`users`.`username`) as `usernames`
from `users_2`
inner join `users` on FIND_IN_SET(`users`.`id`,`users_2`.`user_id`)
Check output here
http://sqlfiddle.com/#!2/c498bc/3
select a.table_2_id,b.username
from users b,users_2 a
where a.table_2_id=b.id
and b.id in(a.user_id)
group by a.table_2_id
First of all, you should not store a multiple value in a single field. For table users_2, the data should be:
table_2_id user_id
1 2
1 4
After you normalized your table, you can use mysql GROUP_CONCAT() to get the result in the format you mentioned
SELECT
users_2.table_2_id,
GROUP_CONCAT(users.username) AS username
FROM
users_2
JOIN
users ON users.id = users_2.user_id
GROUP BY
users_2.table_2_id
;

Getting the last row in each group by?

Hello basically im trying to copy the messaging system that facebook has onto my site.
This is the logic...
"When a user1 CREATES A NEW MESSAGE to send to user7, A new thread is created with thread_id of 1(table: messages_thread) and a new entry is inserted into table:messages which is message_id 1(table:messages). When user7 REPLYS to user1's message, message2 is created, and it has a thread_id of 1.
Now when user 1 CREATES A NEW MESSAGE to sent to user7 thread 2 is created, and message 3 is created. When user7 replies to thread2, message 4 is created (hopefully you get the logic.)
Everything is fine. the only problem is i need to select the newest message in the thread but im having trouble with the sql,
This sql that I have as of right now...
SELECT max(message_id) message_id, m.thread_id, m.body, m.user_id,m.to_id, m.message_status, m.new, m.date, u.id, u.displayname, u.username, u.profile_img
FROM messages m INNER JOIN users u ON u.id = m.user_id
WHERE to_id = 7 AND (message_status = 'unread' or message_status='read' or message_status='saved')
group by thread_id Order by message_id Desc LIMIT 10
Produces this...
+------------+-----------+----------------------+---------+-------+----------------+-----+------------+----+--------------+----------+-------------+
| message_id | thread_id | body | user_id | to_id | message_status | new | date | id | displayname | username | profile_img |
+------------+-----------+----------------------+---------+-------+----------------+-----+------------+----+--------------+----------+-------------+
| 6 | 2 | Really nice | 1 | 7 | read | 0 | 1298617367 | 1 | Kenny Blake | imkenee | 28_1 |
| 4 | 1 | Whats good with you? | 1 | 7 | read | 0 | 1298607438 | 1 | Kenny Blake | imkenee | 28_1 |
+------------+-----------+----------------------+---------+-------+----------------+-----+------------+----+--------------+----------+-------------+
This is good but one small problem, it selects the first row in each group and im trying to select the newest (the last row) in each group
how can i do this? here is the tables. Thanks!
Table: Messages_thread
+----+---------+----------------+-------------+-----------+---------------+-------------+------------+
| id | user_id | subject | from_status | to_status | from_s_delete | to_s_delete | date |
+----+---------+----------------+-------------+-----------+---------------+-------------+------------+
| 1 | 1 | Hey Kenny | unread | unread | 0 | 0 | 1298607438 |
| 2 | 7 | Check out this | unread | unread | 0 | 0 | 1298617344 |
+----+---------+----------------+-------------+-----------+---------------+-------------+------------+
Table Messages
+------------+-----------+---------+-------+-----------------------------------------------------------+----------------+-----------------+-----+------------+
| message_id | thread_id | user_id | to_id | body | message_status | is_sent_deleted | new | date |
+------------+-----------+---------+-------+-----------------------------------------------------------+----------------+-----------------+-----+------------+
| 1 | 1 | 1 | 7 | Whats good with you? | read | 0 | 0 | 1298607438 |
| 2 | 1 | 7 | 1 | Nothing Kenny just chilling. Whats up with you though???? | read | 0 | 0 | 1298607473 |
| 4 | 1 | 1 | 7 | Just posted victor how are you man? | read | 0 | 0 | 1298607956 |
| 5 | 2 | 7 | 1 | Look at this poem.... | read | 0 | 0 | 1298617344 |
| 6 | 2 | 1 | 7 | Really nice | read | 0 | 0 | 1298617367 |
| 7 | 2 | 7 | 1 | Yea i know right :) | unread | 0 | 0 | 1298617383 |
+------------+-----------+---------+-------+-----------------------------------------------------------+----------------+-----------------+-----+------------+
Group the threads in a subquery, which will return the last message for each thread:
SELECT m.message_id, m.thread_id, m.body, m.user_id,
m.to_id, m.message_status, m.new, m.date, u.id, u.displayname, u.username, u.profile_img
FROM messages m
INNER JOIN users u ON u.id = m.user_id
INNER JOIN (
SELECT MAX(message_id) MaxMsgIDForThread
FROM messages
WHERE to_id = 7
AND (message_status = 'unread'
or message_status='read'
or message_status='saved')
GROUP BY thread_id
) g ON m.message_id = g.MaxMsgIDForThread
Order by m.message_id Desc
LIMIT 10
The WHERE may need to be moved to the outer query, right now it will pick the last message the meets the criteria, move it to the outer query if you want to skip the thread entirely if the conditions are not met.
You should also consider storing the message status as a ENUM which will help the comparisons.
There is no way to add order to group by
But maybe this works:
SELECT max(message_id) message_id, MAX(m.thread_id), m.body, m.user_id,m.to_id, m.message_status, m.new, m.date, u.id, u.displayname, u.username, u.profile_img
FROM messages m INNER JOIN users u ON u.id = m.user_id
WHERE to_id = 7 AND (message_status = 'unread' or message_status='read' or message_status='saved')
group by thread_id Order by message_id Desc LIMIT 10

Categories