group and get value in table - mysql

I have 2 tables
Users
----------------
user_id | name
----------------
33 | jon
35 | igor
40 | mark
event
-----------------------------------
event_id | user_id | lavel | value
-----------------------------------
1 | 33 | status| 1
2 | 33 | ins | alfa
3 | 33 | time | 14:30
4 | 35 | status| 0
5 | 35 | ins | beta
6 | 35 | time | 14:51
7 | 40 | ins | beta
intended Query Result
------------------------
user_id | name | status
------------------------
33 | jon | 1
35 | igor | 0
40 | mark |
I want the users in the table and their status.
The status is a administration field. Can not be.
Can anyone help with the query?

SELECT u.user_id, u.name,
CASE WHEN e.value IS NULL THEN '' ELSE e.value AS status
FROM users u
LEFT JOIN event e ON e.user_id = u.user_id
WHERE e.lavel = 'status'
If you can, it seems like it would be a much more manageable table if your column headers were like this:
-----------------------------------------
event_id | user_id | status | ins | time
-----------------------------------------

Try this syntax :
select
user.id,
user.name,
event.value
from user inner join event
on user.id=ever.user_id
WHERE event.lavel = 'status';

Related

Return the data based on the statuses from other table in SQL

I have table with users:
+-----------+----------+
| id | name |
+-----------+----------+
| 1 | Joe |
| 2 | Tom |
| 3 | Jack |
| 4 | Tim |
+-----------+----------+
and second table with tasks liked with these users:
+--------------+--------------+--------------+
| id | user_id | status |
+--------------+--------------+--------------+
| 1 | 1 | new |
| 2 | 1 | done |
| 3 | 1 | in_progress |
| 4 | 2 | in_progress |
| 5 | 2 | done |
| 6 | 2 | done |
| 7 | 2 | done |
| 8 | 3 | new |
| 9 | 3 | new |
| 10 | 3 | new |
| 11 | 4 | in_progress |
| 12 | 4 | in_progress |
| 13 | 4 | new |
+--------------+--------------+--------------+
Each task could be in 'new', 'in_progress' or 'done' status.
I would like to get a list of user_ids who do not have any tasks in 'new' status but have a task in 'done' status.
Could anyone help me with this? Thanks in advance!
A variety of ways to accomplish this. Here are just a couple:
Query #1: Use CTEs
with done as (
select distinct user_id
from tasks
where status = 'done'
),
new as (
select distinct user_id
from tasks
where status = 'new'
)
select u.id, u.name
from users u
join done d
on u.id = d.user_id
where u.id not in (select user_id from new);
id
name
2
tom
Query #2: No CTEs
select id, name
from users
where id in (select user_id from tasks where status = 'done')
and id not in (select user_id from tasks where status = 'new');
id
name
2
tom
View on DB Fiddle
select u.id , u.name,t.status from users u
left join tasks t on t.user_id = u.id
where t.status<>'new';

Get values from 3 tables into a summarized table SQL

I've tried other solutions I've found here but I don't get the correct information back.
I have a table with many different records. A list of names with a status of active. Then I have another table which holds information for each name with a ticket number and then an assignment 'Assigned' and 'Feedback'. Not all names have a ticket.
Then 1 more table that holds a number of hours that goes towards that ticket number.
I want a summary of this information for each name whether there is info there or not. So I started with a subquery here is what I have.
select z.name as 'Name', round(coalesce(sum(x.Hours),0),2) as "Assigned",
round(coalesce(sum(y.Hours),0),2) as "Feedback" from
(select name from namelist where status = 'Active') as z
left join
(select e.realname as "Name", b.id as "Ticket", b.status as "Status", c.value -
COALESCE(sum(a.Hours),0) as "Hours" from user_table e
join ticket_table b ON b.handler_id = e.id
join custom_table c ON c.bug_id = b.id AND c.field_id = 7
left custom_table d ON d.bug_id = b.id AND d.field_id = 15
left hours_table a ON a.Ticket = b.id
where (b.status = 50)
Group By b.id
ORDER BY `Name` ASC, `Status` DESC) x on z.Name= x.Name
left JOIN
(select e.realname as "Name", b.id as "Ticket", b.status as "Status", c.value -
COALESCE(sum(a.Hours),0) as "Hours" from user_table e
join ticket_table b ON b.handler_id = e.id
join custom_table c ON c.bug_id = b.id AND c.field_id = 7
left custom_table d ON d.bug_id = b.id AND d.field_id = 15
left hours_table a ON a.Ticket = b.id
where (b.status = 20)
Group By b.id
ORDER BY `Name` ASC, `Status` DESC) y on z.Name= y.Name
Group by Name
I've changed some of the names around but this is the basic idea. b.status = 50 means Assigned, and 20 means Feedback. Those joins create a table that looks like this:
---------------------------------------------------------------------------------------------------
| Name | Ticket | Status| Hours ((value from custom_table)-(sum from hours table based on ticket))|
| Joe | 234 | 50 | 20 |
| Joe | 235 | 50 | 30 |
| Joe | 236 | 50 | 40 |
| John | 233 | 50 | 10 |
| John | 237 | 50 | 20 |
| John | 238 | 50 | 20 |
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
| Name | Ticket | Status| Hours ((value from custom_table)-(sum from hours table based on ticket))|
| Joe | 134 | 20 | 60 |
| Joe | 135 | 20 | 30 |
| Joe | 136 | 20 | 40 |
| John | 133 | 20 | 70 |
| John | 137 | 20 | 20 |
| John | 138 | 20 | 20 |
---------------------------------------------------------------------------------------------------
-----------------
| Name | Status |
| Joe | Active|
| John | Active|
| Mary | Active|
| Tom | Active|
| John |Inactive|
-----------------
Desired result:
----------------------------
| Name | Assigned| Feedback|
| Joe | 90 | 130 |
| John | 50 | 110 |
| Mary | 0 | 0 |
| Tom | 0 | 0 |
----------------------------
Now the Hours table is c.value which is a 1 to 1 relation subtract sum(hours) from hours table 1 to many relationship.
If I take out one of the joins, the table works. When I put them together like this, the numbers are incorrect. I can get the assigned correct if I only use that join. I can get the feedback numbers correct if I only use the feeback join. However it doesn't work when trying to get either from them. Let me know if you need more info I'll try my best to provide.
Example results:
----------------------------
| Name | Assigned| Feedback|
| Joe | 392 | 145 |
| John | 125 | 94 |
| Mary | 0 | 0 |
| Tom | 0 | 0 |
----------------------------
If I just use the table with status 50.
----------------------------
| Name | Assigned|
| Joe | 90 |
| John | 50 |
| Mary | 0 |
| Tom | 0 |
----------------------------
If I just use the table with status 20.
----------------------------
| Name | Assigned|
| Joe | 130 |
| John | 110 |
| Mary | 0 |
| Tom | 0 |
----------------------------
Don't worry about the custom tables so much, there is a reason they are there but aren't a part of my question. The biggest thing is simply getting the c.value from there, the other join to that table is only for another status, but not relevant to what I'm trying to accomplish.
The two Left Joins seem identical to me apart from the status (unless I am missing something)
Have you tried using a single left join and then an aggregation with a Case statement i.e.
SELECT Name,
SUM(CASE WHEN Status = 50 THEN Hours ELSE 0 END) AS Assigned,
SUM(CASE WHEN Status = 20 THEN Hours ELSE 0 END) AS Feedback
FROM table
GROUP BY Name
I appreciate the answer here is over-simplified but it's more a suggestions since I don't know the content of all the tables mentioned in the query
SQL FIDDLE Example (apologies using SQL SERVER but logic in MySQL is the same for this simple example)
http://sqlfiddle.com/#!18/f77e4/5/0
The output matches the desired results but the issue might lie with another table.
This assumes a single table but the logic should work the same using a left join

Select only most recent records from all results where username = x?

I am currently trying to create some form of instant messenger for my website, allowing users to communicate with one another. To do this, I created a sql table, called messages with the headings id, senderID, recipientID, timestamp, message.
At the moment, I am trying to work out how to create a list of all conversations (not individual messages) for a given user with id = x. This list should contain only the most recent message sent to user x, from each sender y1, y2, y3, ...
For example, consider the table
-------------------------------------------------------------
| ID | senderID | recipientID | timestamp | message |
-------------------------------------------------------------
| 1 | 14 | 34 | 2017-06-21 | Hello ... |
| 2 | 14 | 37 | 2017-06-22 | How ar... |
| 3 | 11 | 34 | 2017-06-23 | I was ... |
| 4 | 17 | 34 | 2017-06-24 | Good ... |
| 5 | 18 | 34 | 2017-06-25 | My na ... |
| 6 | 11 | 34 | 2017-06-26 | I've ... |
| 7 | 14 | 34 | 2017-06-27 | Thank ... |
| 8 | 12 | 34 | 2017-06-28 | I nee ... |
| 9 | 17 | 34 | 2017-06-29 | Have ... |
| 10 | 17 | 34 | 2017-06-30 | You h ... |
-------------------------------------------------------------
Now, suppose that I am user 34 and I wish to view a list containing the most recent message from each senderID to myself. What is the SQL query that would do this? I.e. what SQL query would give the following result:
-------------------------------------------------------------
| ID | senderID | recipientID | timestamp | message |
-------------------------------------------------------------
| 5 | 18 | 34 | 2017-06-25 | My na ... |
| 6 | 11 | 34 | 2017-06-26 | I've ... |
| 7 | 14 | 34 | 2017-06-27 | Thank ... |
| 8 | 12 | 34 | 2017-06-28 | I nee ... |
| 10 | 17 | 34 | 2017-06-30 | You h ... |
-------------------------------------------------------------
What SQL commands are used to give this result?
Here is one method:
select m.*
from messages m
where m.recipientId = 34 and
m.timestamp = (select max(m2.timestamp)
from messages m2
where m2.senderId = m.senderId and m2.recipientId = m.recipientId
);
IN, EXISTS, and JOIN/GROUP BY would all do similar things.
SELECT * FROM messages WHERE recipientId = 34 ORDER BY timestamp DESC;
You could create a second query to get MAX(timestamp) group by recipientID and senderID and just join with the messages table on those same fields and ORDER BY timestamp ASC.
That way, you filter only the last message sent from each senderID to the specified recipientID in the WHERE clause.
select m.*
from messages as m
join ( select recipientID, senderID, max(timestamp) as timestamp
from messages
group by recipientID, senderID ) as l
on m.recipientID = l.recipientID
and m.senderID = l.senderID
and m.timestamp = l.timestamp
where m.recipientID = 34
order by m.timestamp asc
You can find a working SqlFiddle here http://www.sqlfiddle.com/#!9/63a42/18
here is my answer:
create a table named messages_latest, the columns is same with the table messages;
when one user with id = 1 send message to user with id = 34, first remove message from table messages_latest where senderID = 1 and recipientId = 34, and then insert latest record into messages_latest;
the table message_latest saves the most recent messages.

Getting data from a table meeting some requirements

I'm stuck in a SQL logic problem.
I have a table "games" with some data where player1_id and player2_id are user ids that played with each other on a checkers match:
Each game starts with a different ambient, already specified in another table (keyed by "game_id" column).
Assuming that everybody is online, an user can't replay the same game.
How can I select only users that wasn't played the games I didn't played yet to match with me?
An AJAX call will match two users that didn't played an specific game yet and put them to play.
No matter if the user was player1 or player2 , he can't repeat a game.
Thank you very much.
Tables:
game_match
+----+---------+------------+------------+
| id | game_id | player1_id | player2_id |
+----+---------+------------+------------+
| 1 | 1 | 16 | 17 |
| 2 | 1 | 18 | 23 |
| 3 | 1 | 19 | 21 |
| 4 | 1 | 20 | 22 |
| 5 | 2 | 20 | 17 |
| 6 | 2 | 16 | 18 |
| 7 | 2 | 19 | 23 |
| 8 | 1 | 25 | 15 |
+----+---------+------------+------------+
Users
+----+-----------+
| id | name |
+----+-----------+
| 17 | Donald |
| 18 | Margarida |
| 19 | Daisy |
| 20 | Mickey |
| 21 | Steve |
| 22 | Raul |
| 23 | Janis |
| 24 | Michael |
| 25 | Sergio |
| 26 | Bill |
| 27 | Alina |
| 28 | Alana |
| 29 | Harumi |
| 30 | Danielle |
| 31 | Lisa |
+----+-----------+
Thank you!
Assuming you have a table named games and a $userid, you can do this readily with not exists:
select g.*
from games g
where not exists (select 1
from game_match gm
where gm.game_id = g.game_id and gm.player1_id = $userid
) or
not exists (select 1
from game_match gm
where gm.game_id = g.game_id and gm.player2_id = $userid
) ;
Note that you can implement the same logic with or and one subquery. However, with the right indexes, two subqueries are more efficient.
To get your users I would use a union in a subquery:
select *
from users
where id not in
(select player1_id as played
from game_match
where player2_id = #logged_in_user
union
select player2_id
from game_match
where player1_id = #logged_in_user
) as played
Try the following solution using NOT EXISTS and INNER JOIN:
select name
from Users AS u
where not exists(
select 1
from game_match AS gm INNER JOIN
(select distinct game_id
from game_match
where #current_user_id = player1_id OR #current_user_id = player2_id) gids
USING(game_id)
where u.id = gm.player1_id OR u.id = gm.player2_id
);

Joining 3 tables

First off, sorry if this is a near enough duplicate. I've found this question, which nearly does what I want, but I couldn't wrap my head around how to alter it to my needs.
I've got these 3 tables:
cs_Accounts:
+----+-----------------------------+-------------+
| id | email | username |
+----+-----------------------------+-------------+
| 63 | jamasawaffles#googlil.com | jamwaffles2 |
| 64 | jamwghghhfles#goomail.com | jamwaffles3 |
| 65 | dhenddfggdfgetal-pipdfg.com | dhendu9411 |
| 60 | jwapldfgddfgfffles.co.uk | jamwaffles |
+----+-----------------------------+-------------+
cs_Groups:
+----+-----------+------------+-------------+
| id | low_limit | high_limit | name |
+----+-----------+------------+-------------+
| 1 | 0 | 0 | admin |
| 2 | 1 | 50 | developer |
| 3 | 76 | 100 | reviewer |
| 4 | 51 | 75 | beta tester |
| 5 | 1 | 50 | contributor |
+----+-----------+------------+-------------+
cs_Permissions:
+----+---------+----------+
| id | user_id | group_id |
+----+---------+----------+
| 4 | 60 | 4 |
| 3 | 60 | 1 |
| 5 | 60 | 2 |
| 6 | 62 | 1 |
| 7 | 62 | 3 |
+----+---------+----------+
I've been wrestling with a 3 way join for hours now, and I can't get the results I want. I'm looking for this behaviour: a row will be returned for every user from cs_Accounts where there is a row in cs_Permissions that contains their ID and the ID of a group from cs_Groups, as well as the group with the group_id has a high_lmiit and low_limit in a range I can specify.
Using the data in the tables above, we might end up with something like this:
email username cs_Groups.name
----------------------------------------------------------
jwapldfgddfgfffles.co.uk jamwaffles admin
jwapldfgddfgfffles.co.uk jamwaffles developer
jwapldfgddfgfffles.co.uk jamwaffles beta tester
dhenddfggdfgetal-pipdfg.com dhendu9411 admin
dhenddfggdfgetal-pipdfg.com dhendu9411 reviewer
There is an extra condition, however. This condition is where rows are only selected if the group the user belongs to has a high_limit and low_limit with values I can specify using a WHERE clause. As you can see, the table above only contains users with rows in the permissions table.
This feels a lot like homework but with a name like James I'm always willing to help.
select a.email,a.username,g.name
from cs_Accounts a
inner join cs_Permissions p on p.user_id = a.id
inner join cs_Groups g on g.id = p.Group_id
where g.low_limit > 70
and g.high_limt < 120
This is the query
SELECT ac.email, ac.username, gr.name
FROM cs_Accounts AS ac
LEFT JOIN cs_Permissions AS per ON per.user_id = ac.id
INNER JOIN cs_Groups AS gr ON per.user_id = gr.id
You can add a WHERE clause to this query if you want