I have a table called "message" and I want to show all talk between users (last message)
Table structure:
message_id | user_id | recipient_id | message | status | date
Example rows:
1 | 1 | 2 | Hello | 0 | 2016-03-26 12:00:00
2 | 2 | 1 | Hi | 0 | 2016-03-26 12:05:00
3 | 1 | 3 | Are you there? I want meet you! :P | 0 | 2016-03-26 12:20:00
4 | 1 | 2 | How are you? | 0 | 2016-03-26 12:10:00
5 | 2 | 1 | Fine :) | 0 | 2016-03-26 12:15:00
6 | 5 | 1 | Hi :D | 0 | 2016-03-26 15:00:00
So, result should be (for user_id == 1):
3 | 1 | 3 | Are you there? I want meet you! :P | 0 | 2016-03-26 12:20:00
5 | 2 | 1 | Fine :) | 0 | 2016-03-26 12:15:00
6 | 5 | 1 | Hi :D | 0 | 2016-03-26 15:00:00
First you sort by date, then you group by user_id
SELECT *
FROM
(
SELECT * from messages
WHERE `user_id`=1 or `recipient_id`=1
ORDER BY `date` DESC
) m
GROUP BY `user_id`
Result:
3 | 1 | 3 | Are you there? I want meet you! :P | 0 | 2016-03-26 12:20:00
5 | 2 | 1 | Fine :) | 0 | 2016-03-26 12:15:00
6 | 5 | 1 | Hi :D | 0 | 2016-03-26 15:00:00
sqlFiddle demo
I hope I will explain better than in my comment, here it goes:
First, you need to have logging system, so when user logins you save his ID to session.
Second, based on user that is logged you show all messages in "inbox" that he has with other users,select * from message where user_id = $_SESSION['id'], you can join tables and show it names from user and recipient
Third when he clicks on some chat with other person then you show all messages between them ordered by date based on user id and recipient_id
Would a query like select * from messages group by user_id order by date sort you? Fiddle demo.
Related
My question is:
I have a datebase like this:
| from | to | time | text | read |
| hans | poul | 0916 | hi there | 1 |
| john | poul | 1033 | waz up | 1 |
| hans | john | 1145 | new text | 0 |
| poul | john | 1219 | message | 0 |
| poul | hans | 1233 | respond | 0 |
I want an output where every "from" or "to" has 'hans' listed, grouped and order by time like this:
poul - 1233 - respond - 0
john - 1145 - new text - 0
Your sql query could be :-
select * from `table_name` where (`from` ='hans' or `to` ='hans') group by `from`, `to` order by time desc
Post back if you find any difficulties.
My table columns are :
--------------------------------------------------------------------
| EVENT_ID | EVENT_WORKDAY | EVENT_PLACE | EVENT_TIME | EVENT_TYPE |
--------------------------------------------------------------------
Basically, it's a log of what a person did at work. What I want to do is to know how much time the person spent in a particular place.
EVENT_WORKDAY is what will be pased into WHERE argument (I already know at which workdays he was in that place)
EVENT_PLACE is an id of a place (it might be 1, 2 or 3)
EVENT_TIME is a datetime field
EVENT_TYPE is a type of event (1 - at some place, 2 - having a break, 3 - outside)
For example:
A person has started logging at 6:00 being outside
(EVENT_TYPE=3, EVENT_PLACE=null). Then at 6:15 moved to a place (EVENT_PLACE=1, EVENT_TYPE=1), he continued to log it every 15 minutes till 9:53, when he went for a break (EVENT_TYPE=2, EVENT_PLACE=null), at 10:22 he changed the place EVENT_TYPE=1, EVENT_PLACE=2
What I want to get is the time spent at place 1. It must be the time between first event and event at 9:53. So the output must be, that he was in place 1 for 3 hours 38 minutes (or its equivalent in minutes/seconds etc.)
-----------------------------------------------------------------------------
| EVENT_ID | EVENT_WORKDAY | EVENT_PLACE | EVENT_TIME | EVENT_TYPE |
-----------------------------------------------------------------------------
1 | 1 | null | 2016-04-02 06:00:00 | 3
2 | 1 | 1 | 2016-04-02 06:15:00 | 1
3 | 1 | 1 | 2016-04-02 06:30:00 | 1
4 | 1 | 1 | 2016-04-02 06:45:00 | 1
... ...
15 | 1 | 1 | 2016-04-02 09:45:00 | 1
16 | 1 | null | 2016-04-02 09:53:00 | 2
17 | 1 | 2 | 2016-04-02 10:22:00 | 1
I have a MySQL table with the following structure:
| id | date | type | user | approved |
======================================================
| 1 | 2015-01-30 20:32:01 | 2 | 1 | 0 |
| 2 | 2015-01-31 19:40:12 | 1 | 2 | 1 |
| 3 | 2015-02-01 11:12:08 | 2 | 1 | 0 |
| 4 | 2015-02-01 11:32:13 | 4 | 3 | 1 |
| 5 | 2015-02-01 17:25:22 | 6 | 2 | 1 |
I now would like to cumulate the times a task was approved (1) for each user. This is what the result should be:
user 1 --> 0
user 2 --> 2
user 3 --> 1
Is there a way to accomplish this by a single SQL query or would I need to do this outside of MySQL in my php script?
you can just group and summarize values:
select user, sum(approved)
from table
group by user
I have the following 3 tables: unit, stage, stats.
unit stage
+----+--------+ +----+-------+---------------------+
| id | status | | id |unit_id| date |
+----+--------+ +----+-------+---------------------+
| 1 | 2 | | 1 | 2 | 2013-11-22 00:00:00 |
| 2 | 3 | | 2 | 2 | 2013-11-26 12:00:00 |
| 3 | 3 | | 3 | 3 | 2013-10-11 00:00:00 |
| 4 | 0 | | 4 | 1 | 2013-12-29 00:00:00 |
+----+--------+ +----+-------+---------------------+
stats
+----+----------+---------------------+-------+
| id | stage_id | date | clicks|
+----+----------+---------------------+-------+
| 1 | 1 | 2013-11-22 00:00:00 | 10 |
| 2 | 1 | 2013-11-23 00:00:00 | 20 |
| 3 | 1 | 2013-11-24 00:00:00 | 25 |
| 4 | 2 | 2013-11-26 00:00:00 | 15 |
| 5 | 2 | 2013-11-27 12:00:00 | 21 |
| 6 | 3 | 2013-12-29 00:00:00 | 8 |
+----+----------+---------------------+-------+
I need a request, that will produce the following response:
+---------+---------------------+-----------------------+
| unit.id | stage.min.date | sum(stats.max.clicks) |
+---------+---------------------+-----------------------+
| 2 | 2013-11-22 00:00:00 | 46 |
| 3 | 2013-12-29 00:00:00 | 8 |
+---------+---------------------+-----------------------+
by the following rules:
1) unit.id - show only units with unit.status=3
2) stage.min.date - minimal stage.date for corresponding unit_id
3) sum(stats.max.clicks) - sum of stats.clicks with max dvalues for each stage_id associated with corresponding unit_id. In my example 46 = 25(stage_id=1) + 21(stage_id=2)
The problem is in min.date and sum of clicks - I have no idea how to get it in one query. Definitely it`s not a problem to do it using php code and several requests.
Schema in SQL Fiddle
Thanks in advance.
I just ask myself, why I do this? Your example resonse has an error, and does not match your fiddle... but:
SELECT
cc.unit_id, MIN(cc.date) as stage_min_date , SUM(dd.clicks) as stats_max_clicks
FROM
stage cc
LEFT JOIN (
SELECT
bb.stage_id, bb.clicks
FROM
stats bb LEFT JOIN (
SELECT id, stage_id, MAX(date) AS max_date
FROM stats
GROUP BY stage_id
) aa
ON
aa.max_date = bb.date
WHERE
aa.max_date IS NOT NULL
) dd
ON cc.id = dd.stage_id
LEFT JOIN unit ee
ON ee.id = cc.unit_id
WHERE ee.status = 3
GROUP BY cc.unit_id
...
When trying to execute this query my mysql server cpu usage goes to 100% and the page just stalls. I setup an index on (Client_Code, Date_Time, Time_Stamp, Activity_Code, Employee_Name, ID_Transaction) it doesn't seem to help. What steps can I go about next to fix this issue? Also there is already one index on the database if that matters any. Thanks
Here is what this query does
Database info
ID_Transaction | Client_Code | Employee_Name | Date_Time |Time_Stamp| Activity_Code
1 | 00001 | Eric | 11/15/10| 7:30AM | 00023
2 | 00001 | Jerry | 11/15/10| 8:30AM | 00033
3 | 00002 | Amy | 11/15/10| 9:45AM | 00034
4 | 00003 | Jim | 11/15/10| 10:30AM | 00063
5 | 00003 | Ryan | 11/15/10 | 12:00PM | 00063
6 | 00003 | bill | 11/14/10 | 1:00pm | 00054
7 | 00004 | Jim | 11/15/10 | 1:00pm | 00045
8 | 00005 | Jim | 11/15/10| 10:00 AM| 00045
The query takes the info above and counts it like so. By the most recent entry for each client_code. In this case the query would look like this. After php.
Jerry = 1
2 | 00001 | Jerry | 11/15/10| 8:30AM | 00033
Amy = 1
3 | 00002 | Amy | 11/15/10| 9:45AM | 00034
Ryan = 1
5 | 00003 | Ryan | 11/15/10 | 12:00PM | 00063
Jim = 2
7 | 00004 | Jim | 11/15/10 | 1:00pm | 00045
8 | 00005 | Jim | 11/15/10| 10:00 AM| 00045
$sql = "SELECT m.Employee_Name, count(m.ID_Transaction)
FROM ( SELECT DISTINCT Client_Code FROM Transaction)
md JOIN Transaction m ON
m.ID_Transaction = ( SELECT
ID_Transaction FROM Transaction mi
WHERE mi.Client_Code = md.Client_Code AND Date_Time=CURdate() AND Time_Stamp!='' AND
Activity_Code!='000001'
ORDER BY m.Employee_Name DESC, mi.Client_Code DESC, mi.Date_Time DESC,
mi.ID_Transaction DESC LIMIT 1 )
group by m.Employee_Name";
Is there a better way to write this query so it doesnt bog down my system? The query works fine with 10 database entries but it locks my server up when the database has 300,000 entries.
Thanks
Eric
+----+--------------------+-------------+--------+------------------------+--------------+---------+----------------+------+----------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+-------------+--------+------------------------+--------------+---------+----------------+------+----------+----------------------------------------------+
| 1 | PRIMARY | <derived2> | ALL | [NULL] | [NULL] | [NULL] | [NULL] | 8 | 100.00 | Using temporary; Using filesort |
| 1 | PRIMARY | m | index | [NULL] | search index | 924 | [NULL] | 21 | 100.00 | Using where; Using index; Using join buffer |
| 3 | DEPENDENT SUBQUERY | mi | ref | search index,secondary | search index | 18 | md.Client_Code | 3 | 100.00 | Using where; Using temporary; Using filesort |
| 2 | DERIVED | Transaction | index | [NULL] | secondary | 918 | [NULL] | 21 | 38.10 | Using index |
+----+--------------------+-------------+--------+------------------------+--------------+---------+----------------+------+----------+----------------------------------------------+
What about going with multiple GROUP BY's instead of the all the sub queries to simplify things.... something like:
SELECT * FROM Transaction WHERE Date_Time=CURdate() AND Time_Stamp!='' AND Activity_Code != '000001' GROUP BY Client_Code, Employee_Name
If I'm understanding your query correctly then something like this would solve the issues and prevent the need for sub queries.
You'll definitely want to do a join instead of a sub select.
Also, how many records are you viewing? Is pagination and using limit out of the question?
If you set up your initial query modified with inner/outer joins as a view and it doesn't crash, you'll be one step closer. Once the view is set up, you'll be able to use a much less complicated select statement - potentially paginated.