Select by latest timestamp - php

I have a following table :
+-------+--------+---------------------+
| score | user | scrap_time |
+-------+--------+---------------------+
| 200 | Bob | 2015-09-08 11:46:17 |
+-------+--------+---------------------+
| 210 | Alice | 2015-09-08 11:46:17 |
+-------+--------+---------------------+
| 240 | Bob | 2015-09-08 11:48:00 |
+-------+--------+---------------------+
| 260 | Alice | 2015-09-08 11:48:01 |
+-------+--------+---------------------+
I want to get all the scores for each user that have the latest scrap_time and ignore the older ones.
Example:
+-------+--------+---------------------+
| score | user | scrap_time |
+-------+--------+---------------------+
| 240 | Bob | 2015-09-08 11:48:00 |
+-------+--------+---------------------+
| 260 | Alice | 2015-09-08 11:48:01 |
+-------+--------+---------------------+
I have been trying to come up with a query, like this one :
select * from scores where date(scrap_time) = ( select max(scrap_time) from scores);
But this does not give me the results I need.

First you need to find MAX(scrap_time) per user and then find those rows
SELECT * FROM scores WHERE (user,scrap_time) IN (
SELECT user,MAX(scrap_time) scrap_time FROM scores
GROUP BY user);

You need to get the MAX(scrap_time) per user, then simply join back to your table to get the required result set. Something like the following should work:
SELECT s.score, s.user, s.scrap_time
FROM scores AS s
INNER JOIN (SELECT user, max(scrap_time) AS maxTime
FROM scores
GROUP BY user) AS t
ON s.user = t.user AND s.scrap_time = maxTime
Demo here

use max function with group by which will provide u recent time of each score
select score, user, max(scrap_time)
from scores
group by score;

Related

MySQL - Average of Unique rows

If I have three columns:
id, user, points
My data is:
+-------+------------------+-------------+
| id | user | points |
+-------+------------------+-------------+
| 1 | A | 100 |
+-------+------------------+-------------+
| 1 | A | 200 |
+-------+------------------+-------------+
| 2 | B | 300 |
+-------+------------------+-------------+
| 2 | B | 400 |
+-------+------------------+-------------+
I would like to have the average of ONLY the max points of each user.
For this exmple I want to get as results: 300 points ((200+400)/2).
When I use the following Mysql query, I get: 250:
SELECT avg(points) FROM table
SQL DEMO
Try this :
SELECT avg(points) FROM (
SELECT max(points) as points FROM table1 group by id
) as T
Firstly get the max points of each user and then get the AVG from them.
You should first get the max group by use and the the avg of this subquery
SELECT AVG(points)
FROM (SELECT MAX(points) FROM your_table GROUP BY user) subt

Issue with order by and group by with two foreign keys in same table

I need to develop chat application in php for this i have created two tables likes users and message. every user details will be stored in users table and every message will be stored in messages table.I have done storing part it is working fine. Now i need to display messages.So as per my requirement.
when any user logs into his portal he/she will be able to see latest messaged users list.And if he want to message any of other users ,he just clicks on there profile pic than a message panel will be opened .Untill here i completed everything.
But my issue is i need to display
latest messaged users list,
in this i need to show user first name, profile picture,last message, last message date.
And one more condition is i need to display the list like latest messaged user first.
I have tried in many ways but i got users list with first message i don't want like that i need last message for that user
My tables are
Users table
uid | firstname | email | mobile
---------------------------------------------
1 | kumar | kumar#gmail.com | 9876543210
----------------------------------------------
2 | jack | jack#gmail.com | 8876543216
----------------------------------------------
3 | rams | rams#gmail.com | 7876543215
----------------------------------------------
4 | devid | devid#gmail.com | 9876543220
----------------------------------------------
5 | joe | joe#gmail.com | 8876543212
----------------------------------------------
messages table
mid| from_id | to_id | message | created_at
----------------------------------------------------------------
1 | 1 | 2 | hello jack | 2017-02-03 09:00:52
----------------------------------------------------------------
2 | 2 | 1 | hi kumar | 2017-02-03 09:10:30
----------------------------------------------------------------
3 | 2 | 3 | ram where are you | 2017-02-03 09:15:02
----------------------------------------------------------------
4 | 3 | 2 | at home | 2017-02-03 09:35:20
----------------------------------------------------------------
5 | 1 | 2 | hello how are you | 2017-02-03 09:42:55
----------------------------------------------------------------
6 | 4 | 2 | good morning | 2017-02-03 09:50:45
----------------------------------------------------------------
8 | 1 | 3 | hi | 2017-02-03 09:54:22
----------------------------------------------------------------
7 | 3 | 1 | hello kumar | 2017-02-03 09:58:38
----------------------------------------------------------------
For example i have logged in as kumar(uid=1)
Expected output:
firstname | message | mid | uid
-----------------------------------------
rams | hello kumar | 7 | 3
-----------------------------------------
jack | hello how are you | 5 | 2
-----------------------------------------
I have tried like this :
SELECT DISTINCT
`u`.`firstname`,
`u`.`profile_photo`,
`u`.`uid`,
`u2`.`firstname`,
`u2`.`profile_photo`,
`u2`.`uid`,
`message`,
`messages`.`created_at`,
`messages`.`from_id`,
`messages`.`to_id`,
`messages`.`mid`
FROM
`messages`
INNER JOIN
`users` AS `u` ON `u`.`uid` = `messages`.`from_id`
INNER JOIN
`users` AS `u2` ON `u2`.`uid` = `messages`.`to_id`
WHERE
(from_id = 1 OR to_id = 1)
GROUP BY
`u`.`uid`,
`u2`.`uid`
ORDER BY
`messages`.`mid` DESC
But got output like this
firstname | message | mid | uid
-----------------------------------------
jack | hello jack | 1 | 2
-----------------------------------------
rams | hi | 5 | 2
-----------------------------------------
Thanks in advance
try this way
SELECT DISTINCT `u`.`firstname`,`u`.`profile_photo`, `u`.`uid`, `u2`.`firstname`,`u2`.`profile_photo`,`u2`.`uid`, `message`,`messages`.`created_at`, `messages`.`from_id`,`messages`.`to_id`,`messages`.`mid`
FROM `messages`
INNER JOIN `users` AS `u` ON `u`.`uid` = `messages`.`from_id`
INNER JOIN `users` AS `u2` ON `u2`.`uid` = `messages`.`to_id`
WHERE (from_id = 1 OR to_id = 1)
GROUP BY `u`.`uid`, `u2`.`uid`
ORDER BY `messages`.`created_at` DESC
It appears that you want to put messages in the same group if they're between the same two users, regardless of the direction. To do this, change your GROUP BY to:
GROUP BY GREATEST(u.uid, u2.uid), LEAST(u.uid, u2.uid)
Use this along with the solutions in SQL Select only rows with Max Value on a Column to get the first or last message in each conversation found using this grouping.
You should also give aliases to the columns from u and u2 in the SELECT clause, so you can distinguish the sender and receiver information in the result.
SELECT u.firstname AS sender_name, u.profile_photo AS sender_photo, ...
Or since one of the users is always kumar, you could just select only the information about the other user:
SELECT IF(from_id = 1, u2.firstname, u1.firstname) AS firstname,
IF(from_id = 1, u2.profile_photo, u1.profile_photo) AS profile_photo,
...

MYSQL: Get rows that match criteria

I have a table that contains users where they have set a minium age and maxium age they want to be shown to.
Table looks like this:
=========================================
| id | username | age | minAge | maxAge |
=========================================
| 1 | Clark | 20 | 16 | 50 |
-----------------------------------------
| 2 | Kent | 33 | 22 | 25 |
-----------------------------------------
| 3 | Bruce | 45 | 18 | 25 |
-----------------------------------------
| 4 | Wayne | 40 | 23 | 45 |
-----------------------------------------
If 'Clark' is logged in, he will see: 'Bruce'.
If 'Kent' is logged in, he will see: 'Clark', 'Wayne'.
If 'Bruce' is logged in, he will see: 'Clark', 'Wayne'.
If 'Wayne' is logged in, he will see: 'Clark'.
No one will see 'Kent', because no one is in his visible range.
How would something like this work?
I have looked at something like this:
SELECT * FROM table_user WHERE age BETWEEN '16' AND '50';
But this of course is the other way around.
This is a join on the age column, using between (or similar logic). The challenge is getting the tables in the right order:
select u.username, group_concat(tosee.user_name) as users_seen
from table_user u left join
table_user tosee
on tosee.age between u.minage and u.maxage and
tosee.username <> u.username
group by u.username;

MySQL - Combine tables and order by max date

I have two mysql tables which I've simplified below. I would like to create a query which would pull the data from both tables and order by the most recent date. So if there's an entry (or entries) in the notes table it would look for the most recent notes_date for that cid, and if there's no entry it would use the contact_date for that cid.
contacts
+-----+--------+---------------------+
| cid | name | contact_date |
+-----+------------------------------+
| 1 | george | 2014-03-03 12:24:48 |
| 2 | john | 2014-02-28 15:39:20 |
| 3 | paul | 2014-02-14 10:13:58 |
| 4 | ringo | 2014-02-06 07:13:17 |
+-----+--------+---------------------+
notes
+-----+-----+---------------------+
| nid | cid | notes_date |
+-----+---------------------------+
| 1 | 1 | 2014-03-06 15:43:55 |
| 2 | 1 | 2014-03-14 20:14:12 |
| 3 | 4 | 2014-03-20 22:10:14 |
+-----+-----+---------------------+
This is the result I'd like to get from the query
4 ringo 2014-03-20 22:10:14
1 george 2014-03-14 20:14:12
2 john 2014-02-28 15:39:20
3 paul 2014-02-14 10:13:58
Any help would be much appreciated
This has a few parts to it. One is getting the most recent date for notes. Another is combining this with the contacts data and then choosing the right date.
The following approach uses an aggregation subquery and join to do the calculation:
select c.cid, c.name, coalesce(n.notes_date, c.contact_date) as thedate
from contacts c left outer join
(select n.cid, max(notes_date) as notes_date
from notes
group by n.cid
) n
on c.cid = n.cid
You should use join. You can have query like-
select cont.cid, cont.name, nots.notes_date from contacts cont inner join notes nots on cont.cid=nots.cid order by nots.notes_date

Selecting multiple tables MySQL and retrieving different data

I have 4 tables that I need to pull data from. I need to count how many people are signed for a single event and see if a user is applied for an event.
These are my table setups:
TABLE: users
+----+----------+-------+--------+-------+
| id | username | level | class | guild |
+----+----------+-------+--------+-------+
| 1 | example1 | 100 | Hunter | blah |
| 2 | example2 | 105 | Mage | blah2 |
| 3 | example3 | 102 | Healer | blah |
+----+----------+-------+--------+-------+
ID is primary
TABLE: event_randoms
+----+----------+-------+--------+----------+----------+
| id | username | level | class | apped_by | event_id |
+----+----------+-------+--------+----------+----------+
| 1 | random1 | 153 | Hunter | 3 | 3 |
| 2 | random2 | 158 | Healer | 3 | 1 |
| 3 | random3 | 167 | Warrior| 1 | 3 |
+----+----------+-------+--------+----------+----------+
ID is primary
apped_by should be foreign key to users.id
event_id should be foreign key to events.id
TABLE: events
+----+------------+------------+-----------+-----------+-----------+
| id | event_name | event_date | initiator | min_level | max_level |
+----+------------+------------+-----------+-----------+-----------+
| 1 | event1 | date1 | 1 | 100 | 120 |
| 2 | event2 | date2 | 1 | 121 | 135 |
| 3 | event3 | date3 | 1 | 100 | 120 |
| 4 | event4 | date4 | 1 | 150 | 200 |
+----+------------+------------+-----------+-----------+-----------+
ID is primary
TABLE: event_apps
+----+----------+--------------+
| id | event_id | applicant_id |
+----+----------+--------------+
| 1 | 3 | 2 |
| 2 | 4 | 2 |
| 3 | 3 | 1 |
| 4 | 1 | 3 |
+----+----------+--------------+
ID is primary
event_id should be foreign key to events.id
applicant_id should be foreign key to users.id
I will be the first to admit that I am very new to this. I just learned how to use MySQL a few days ago. I can grab stuff from a single table, but I am unsure how to grab from multiple tables.
This is the SQL query I tried
SELECT DD_events.id, event_id, applicant_id, guild, level, class, DD_users.id
FROM DD_events, DD_event_apps, DD_users
WHERE DD_event_apps.event_id = DD_events.id
AND DD_event_apps.applicant_id = DD_users.id
and tried to print_r an array but the array turns up empty.
So a few questions pertain to this:
1: How would I count and display as a number how many people (users and randoms) are signed up for an event?
eg: event 3 should have 4 total (2 users and 2 randoms)
2: How do I see if a particular individual is signed for an event and display text based if they are or not?
eg: user 1 is signed up for event 3 so it would be "Registered" but user 2, who is not signed, would display "Not Registered"
3: I want to display info for who is signed for a particular event in 2 tables, 1 for users and another for randoms.
eg: Event 3 would have 2 users info (username, guild, class, level) under the users table and then 2 random users info (name, class, level, what user applied this person) in the random table.
Any and all help is appreciated even if you can answer 1 part.
I'm thinking this would be your base query:
SELECT
event.id,
app.applicant_id,
usr.guild,
usr.level,
usr.class,
usr.id AS Userid
FROM
DD_events event
JOIN
DD_event_apps app
ON (event.id = app.event_id)
LEFT JOIN
DD_users usr
ON (app.user_id = usr.id)
You can make modifications to this to aggregate it, like so:
SELECT
event.id,
COUNT(app.applicant_id) AS ApplicantCount,
COUNT(DISTINCT usr.guild) AS UniqueGuilds,
COUNT(DISTINCT usr.level) AS UniqueLevels,
COUNT(DISTINCT usr.class) AS UniqueClasses,
COUNT(DISTINCT usr.id) AS UniqueUsers
FROM
DD_events event
JOIN
DD_event_apps app
ON (event.id = app.event_id)
LEFT JOIN
DD_users usr
ON (app.user_id = usr.id)
GROUP BY
event.id
I could write those scripts for you, but I think this provides a good starting point for you to continue from. You'll find that T-SQL is fairly simple when you are trying to get the results you are looking for. Hope this helps!
<?php $query = "SELECT count(*) AS numbuh FROM DD_event_apps WHERE event_id = {$row['id']}";
try
{
// These two statements run the query against your database table.
$stmt = $db->prepare($query);
$stmt->execute();
}
catch(PDOException $ex)
{
// Note: On a production website, you should not output $ex->getMessage().
// It may provide an attacker with helpful information about your code.
die("Failed to run query: " . $ex->getMessage());
}
echo($query);
// Finally, we can retrieve all of the found rows into an array using fetchAll
$count = $stmt->fetchAll();
echo($count['numbuh']); ?>

Categories