grouping by time in mysql - php

I have got this query:
SELECT * FROM `mfw_navnode` n1
WHERE (n1.node_name='Eby' OR n1.node_name='Lana' OR n1.node_name='MF' OR n1.node_name='Amur' OR n1.node_name='Asin' )
GROUP BY n1.node_name
It has another field which is called time_added..that is basically the time of each row..I want to order the node_name (Select them), by the latest time I added them.
How do I do it? each node_name has a time.. but I want to group each node_name by the latest time it was added..
I thought to use MAX(time_added) and then add it to group by..but that gave me an error..
What could be a possible solution?

If I understand the question, the following may be what you are looking for. It isn't quite clear to me if you want them ordered with the latest times first or last (add DESC as needed):
SELECT `node_name`, max(`time`) `maxtime` FROM `mfw_navnode` n1 ...
GROUP BY node_name order by `maxtime`;
One thing to note is that the query in the OP, which includes fields not in the GROUP BY clause is ambiguous and is not allowed in most SQL implementations.

SELECT * FROM `mfw_navnode` n1
WHERE (n1.node_name='Eby' OR n1.node_name='Lana' OR n1.node_name='MF' OR n1.node_name='Amur' OR n1.node_name='Asin' )
GROUP BY n1.node_name
ORDER BY n1.time_added DESC
Order by DESC automatically shows most recently created first.

Related

query group by with order by

i need to create query with group by and order by, and i dont know how to do it.
query should return one record for the newest date for existing device_serial_number. enter image description here
so i would to get id 591 nad 592
solution can be in sql or the best way it will be in symfony, through query builder etc.
There are many ways to accomplish what you want.
First Way
The oldest way to select first, best, worst, whatever within a group is with a correlated subquery:
Select * from mytable outer
Where created_at = (
Select max(created_at)
from mytable inner
Where inner.device_serial_number = outer.device_serial_number
)
Second Way
Use a subselect to find earliest dates for all devices, them join back to the original table to filter:
Select a.*
From mytable a Inner Join
(Select device_serial_number, max(created_at) as latedate
From mytable b
Group By device_serial_number
) b
On a.device_serial_number=b.device_serial_number
And a.created_at=b.latedate
Third way
Use a window function to rank order all the dates and then pick the number one ranking.
Select * From (
Select *
, rank() Over (Partition By device_serial_number Order by created_at desc) as myrank
From mytable
)
Where myrank=1
Notice that while these 3 solutions use different aspects of SQL, they all have a common analytical approach. They are all two step processes whose first (inner) part involves finding the most recent created_at date for each device_serial_number and then reapplying that result back to the original table in the second (outer) part.

How to retrieve nested join select statement data from query

I have the following query and am unsure of how to retrieve the 'note' from the nested join query.
This Left join selects the latest note for this customer, but I am not sure how to echo this data...
LEFT JOIN (SELECT note AS latestnote, timestamp, renewalid FROM renewal_note ORDER BY timestamp DESC LIMIT 1) AS n ON n.renewalid=renewal.id
Full Query:
SELECT renewal.id AS rid, renewal.personid, renewal.enddate, renewal.assettype, renewal.producttype, renewal.vrm, renewal.make, renewal.model, renewal.submodel, renewal.derivative, renewal.complete, person.forename, person.surname, person.company, appointment.id AS appid, appointment.renewalid,
(SELECT COUNT(complete) FROM renewal WHERE complete=1 && enddate BETWEEN '".$month_start."' AND '".$month_end."' && dealershipid='".$dealership_id."' && assettype='U' && producttype!='CH' && complete=1) AS renewedcount
FROM renewal
LEFT JOIN person ON person.id=renewal.personid
LEFT JOIN appointment ON appointment.renewalid=renewal.id
LEFT JOIN (SELECT note AS latestnote, timestamp, renewalid FROM renewal_note ORDER BY timestamp DESC LIMIT 1) AS n ON n.renewalid=renewal.id
WHERE enddate BETWEEN '".$month_start."' AND '".$month_end."' && renewal.dealershipid='".$dealership_id."' && assettype='U' && producttype NOT LIKE '%CH%'
ORDER BY enddate ASC
The Below is currently what is returned in each loop (which is working fine), and I can access as normal; $row['COLUMNNAME'].
rid
personid
enddate
assettype
used/new
producttype
vrm
make
model
submodel
derivative
complete
forename
surname
company
appid
renewalid
renewedcount
BUT I also need to be able to get the NOTE from renewal_note (the third LEFT JOIN).
I dont have issues with normal inner joins, But I have never created a query with subqueries, so struggling to echo this data out within the php loop.
(Just to point out that the only reason I am nesting a query is that I need only the latest note for each customer to be returned.)
I have tried $row['latestnote'], (with no success) and I am sure this is definitely not the way to access this data.
Could someone please point me in the right direction?
UPDATE
With updates from the comments, I have tried a much more simplified query (with ALL columns included so can't miss anything out) specifically targetting the subquery:
SELECT
*
FROM
renewal
LEFT JOIN(
SELECT
*
FROM
renewal_note
ORDER BY
TIMESTAMP
DESC
LIMIT 1
) AS n
ON
n.renewalid = renewal.id
But this still returns NULL for every column on the renewal_note.
90% of 'renewal' records have a note linked to them in the renewal_note table, but none showing.
renewal table has a unique primary key; ID.
renewal_note table links via column name: renewalid.
I think I have sussed this out.
Thanks to the commenters :)
Purely posting this for anyone else with similar questions/issues.
To get data from a LEFT JOIN(SELECT... statement; include the alias into the outer SELECT statement. Then you can use $row['columnname'] as normal.
LIMIT 1 on the subquery returned only 1 record for the entire query. Remove LIMIT 1 to show all results for the subquery dependant on your 'link' to the main query.
From what I have tested, ORDER BY seems to be working, but not sure if this is a fluke, or if it just sorting naturally by the primary key; ID

MySQL GROUP By and ORDER BY conflict

So i'm trying to select some contacts (TABLE2) based on their HISTORY (TABLE1).
So I am testing with this SQL Query:
SELECT
contacts_history.userId,
contacts_history.contactId,
contacts_history.dateAdded,
contacts.firstName
FROM
contacts_history
INNER JOIN contacts ON contacts_history.contactId = contacts.contactId
AND contacts_history.userId = contacts.userId
GROUP BY
contacts.contactId
ORDER BY
contacts_history.dateAdded DESC
LIMIT 0, 10
But i'm noticing that i'm not getting the most 'recent' values.
If I remove the GROUP BY I get totally different DATE RANGES.
I have tried using DISTINCT, but no decent response either.
Take a look at the comparison table results.
I'm having a hard time getting the most recent items, without having duplicate contactId's in there.
Any help would be greatly appreciated... i'm sure this is super basic, just not sure why it's not working the best.
GROUP BY is for use with aggregate methods. Without something like MAX(contacts_history.dateAdded) it doesn't make any sense to use GROUP BY
I think what you want is along the lines:
SELECT
contacts_history.userId,
contacts_history.contactId,
MAX(contacts_history.dateAdded) AS last_date,
contacts.firstName
FROM
contacts_history
INNER JOIN contacts ON contacts_history.contactId = contacts.contactId
AND contacts_history.userId = contacts.userId
GROUP BY
contacts_history.userId,
contacts.contactId
contacts.firstName
ORDER BY
last_date DESC
LIMIT 0, 10
This should give you (I haven't tested it) one line for each user and contact, sorted by the date the contact was added.

How can I get this database to order before the GROUP BY [duplicate]

This question already has answers here:
MySQL Order before Group by
(10 answers)
Closed 9 years ago.
I made a website for golf scorecards. The page I am working on is the players profile. When you access a players profile, it shows each course in order of last played (DESC). Except, the order of last played is jumbled due to the ORDER BY command below. Instead, when it GROUPs, it takes the earliest date, rather than the most recent.
After the grouping is done, it correctly shows them in order (DESC)... just the wrong order due to the courses grouping by date_of_game ASC, rather than DESC. Hope this isn't too confusing.. Thank you.
$query_patrol321 = "SELECT t1.*,t2.* FROM games t1 LEFT JOIN scorecards t2 ON t1.game_id=t2.game_id WHERE t2.player_id='$player_id' GROUP BY t1.course_id ORDER BY t1.date_of_game DESC";
$result_patrol321 = mysql_query($query_patrol321) or die ("<br /><br />There's an error in the MySQL-query: ".mysql_error());
while ($row_patrol321 = mysql_fetch_array($result_patrol321)) {
$player_id_rank = $row_patrol321["player_id"];
$course_id = $row_patrol321["course_id"];
$game_id = $row_patrol321["game_id"];
$top_score = $row_patrol321["total_score"];
Try to remove the GROUP BY-clause from the query. You should use GROUP BY only when you have both normal columns and aggregate functions (min, max, sum, avg, count) in your SELECT. You have just normal columns.
The fact that it shows the grouping result in ASC order is a coincidence because that is the order of their insertion. In contrast to other RDBMS like MS SQL Server, MySQL allows you to add non-aggregated columns to a GROUPed query. This non-standard behavior creates the confusion you're seeing. If this were not MySQL, you'd need to define the aggregation for all your selected columns given the grouping.
MySQL's behavior is (I believe) to take the first row matching the the GROUP for non-aggregated columns. I would advise against doing this.
Even though you're aggregating, you're not ORDERing by the aggregated column.
So What you want to do is ORDER BY the MAX date DESC
In this way, you are ordering by the latest date per course (your grouping criteria).
SELECT
t1.* -- It would be better if you actually listed the aggregations you wanted
,t2.* -- Which columns do you really want?
FROM
games t1
LEFT JOIN
scorecards t2
ON t2.[game_id] =t1[.game_id]
WHERE
t2.[player_id]='$player_id'
GROUP BY
t1.[course_id]
ORDER BY
MAX(t1.[date_of_game]) DESC
If you want the maximum date, then insert logic to get it. Don't depend on the ordering of columns or on undocumented MySQL features. MySQL explicitly discourages the use of non-aggregated columns in the group by when the values are not identical:
MySQL extends the use of GROUP BY so that the select list can refer to nonaggregated columns not named in the GROUP BY clause. This means that the preceding query is legal in MySQL. You can use this feature to get better performance by avoiding unnecessary column sorting and grouping. However, this is useful primarily when all values in each nonaggregated column not named in the GROUP BY are the same for each group. The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate. (see [here][1])
How do you do what you want? The following query finds the most recent date on each course and just uses that -- and no group by:
SELECT t1.*, t2.*
FROM games t1 LEFT JOIN
scorecards t2
ON t1.game_id=t2.game_id
WHERE t2.player_id='$player_id' and
t1.date_of_game in (select MAX(date_of_game)
from games g join
scorecards ss
on g.game_id = ss.game_id and
ss.player_id = '$player_id'
where t1.course_id = g.course_id
)
GROUP BY t1.course_id
ORDER BY t1.date_of_game DESC
If game_id is auto incrementing, you can use that instead of date_of_game. This is particularly important if two games can be on the same course on the same date.

MySQL GROUP BY ignoring ORDER BY clause

I have two queries, the only difference being the GROUP BY clause
SELECT * FROM `packages_sorted_YHZ` WHERE `hotel_city` = 'Montego Bay'
ORDER BY `deal_score` DESC
LIMIT 0,3;
SELECT * FROM `packages_sorted_YHZ` WHERE `hotel_city` = 'Montego Bay'
GROUP BY `hotel_name`
ORDER BY `deal_score` DESC
LIMIT 0,3;
The first query returns the first result with a deal_score of 75 but the second query returns the first result with the deal_score of just 72.
I would have thought that regardless of the GROUP BY clause, the first result would have the highest deal score possible (75)
The purpose of the GROUP BY clause is to optionally select a unique hotel_name for each result.
Does anyone know what I'm doing wrong here.
Without being able to look at all the data, my best guess is that Group By is merging the data and giving you an arbitrary value that matches the Where clause. This will happen if hotel name isn't unique, and you won't be given the maximum score unless you specifically query for it.
Try putting a Max() around deal_score. In MySQL, Group By can be used way too easily, I like how MSSQL enforces the use of aggregate functions and grouping by every field that isn't aggregated. Try this query:
SELECT `hotel_name`, MAX( `deal_score` ) AS `max_score` FROM `packages_sorted_YHZ` WHERE `hotel_city` = 'Montego Bay'
GROUP BY `hotel_name`
ORDER BY `max_score` DESC
LIMIT 0,3;
It looks like you are facing some very MySql specific issue. In theory, your second query is not valid and should return an error. But MySQL allows for selection of so called hidden columns - the columns that are not mentioned in a group by clause and not aggregated.
As stated in manual, hidden columns values are indeterminate, but in practice it usually picks up the first row walking the index used, regardless of sorting specified by ORDER BY, as sorting is performed after the grouping.
This is vendor-specific issue, so your second query should always fail if used to query other RDBMS. The correct implementation should be something like
SELECT max(`deal_score`) as maxdeal, `hotel_name` FROM `packages_sorted_YHZ` WHERE `hotel_city` = 'Montego Bay'
GROUP BY `hotel_name`
ORDER BY maxdeal
LIMIT 0,3;
You should not use GROUP BY but instead DISTINCT since you want a unique hotel_name.
example:
SELECT DISTINCT hotel_name -- add other fields here
FROM `packages_sorted_YHZ`
WHERE `hotel_city` = 'Montego Bay'
ORDER BY `deal_score` DESC
LIMIT 0,3;
SELECT max(deal_score) as maxdealscore, `hotel_name` * FROM `packages_sorted_YHZ` WHERE `hotel_city` = 'Montego Bay'
GROUP BY `hotel_name`
ORDER BY `deal_score` DESC
LIMIT 0,3;

Categories