Grouping Fields to display Most Recent Date - mysql

I have a quick question that I can't seem to figure out. I'm trying to list end user items (just an example) with only the most recent comment displayed.
ID Name EventDate Type
1 PC 12/12/2012 End User Items
1 PC 11/12/2012 End User Items
1 PC 10/11/2012 End User Items
2 Mobile 12/12/2012 End User Items
2 Mobile 11/01/2012 End User Items
2 Mobile 12/12/2011 End User Items
3 Server 12/12/2013 Server
So I would try something like this:
select * from systems where type = "End User Items" group by ID
But the result would still not show the latest date.
Any help would be greatly appreciated!

Have you tried getting the MAX date as follows?
SELECT Name,
MAX(EventDate),
Type
FROM systems
WHERE type = 'End User Items'
GROUP BY Name, Type

You can use a subQuery to get the ID and MAX Date and then join back on your systems table with the ID and the MAX date.
SELECT s2.Name, s.EventDate
FROM system s2
INNER JOIN (SELECT ID, MAX(EventDate) EventDate
FROM systems
WHERE type = 'End User Items'
GROUP BY ID) AS s on s2.ID = s.ID AND s2.EventDate = s.EventDate

Define the columns you want to show without summarization as your GROUP BY fields. Select those fields and the calculated summary function columns (eg. max(), sum(), count() ).
SELECT ID, Name, MAX(EventDate) as LastDate
FROM systems
WHERE type = 'End User Items'
GROUP BY ID, Name
You probably want to see ID, and Name. Type is superfluous here, since you only want one Type. You want to get the max() date in the group. All fields returned must either be summary functions, or GROUP BY columns.

Related

Need to retrieve the most recent room type/Rateplan combination (mysql)

I will explain the logic:
I need to retrieve only the most recent room type/rate plan combinations from the rateplan_roomtypeTable.
room type ID and rate plan id are located in separate columns
there are 2 conditions that need to be met: all active room type/rate plan combinations need to be retrieved along with all room type/rate plan combinations that have produced even if they are not active. All these combinations need to be the most recent ones.
The desired results would be like the table I ll share with you:
Your help with the below query will be much appreciated:
select
Id
, RoomTypeId
, RateTypeId
,isactiveRateType
,isactiveRoomType
, RatePlanName
, RoomTypeName
FROM
rateplan_roomtypeTable
where
RateTypeId IN (select RateTypeId from ProductionTable where (cast(bookingdate as date) between date_add('day',-92, current_date) and date_add('day', -2, current_date)))
OR (isactiveRateType = 1 and isactiveRoomType = 1)
GROUP BY
1,2,3,4,5
Thank you

Gathering data from three separate tables, sql

I have three separate tables that represent student attendance for three weeks, respectively. I want to be able to generate four columns that break down the attendance by week for each of the students. If a student was present multiple times a week, the number of times present should be added. Also, if a student was present in one week and not the next, it would get 1 for the month present (assuming it was only present once) and and 0 for the one absent. I have tried to multiple variations of count() and joins but to no avail. Any help would be greatly appreciated. The following is a truncated fiddle:
http://www.sqlfiddle.com/#!9/b847a
Here is a sample of what I am trying to achive:
Name | CurrWeek | LastWeek | TwoWkAgo
Paula | 0 | 2 | 3
Rather than three tables you should have only one with a column for the week. So naturally one solution for your request is to build it on-the-fly with UNION ALL:
select
name,
sum(week = 'currentWeek') as currentWeek,
sum(week = 'lastWeek') as lastWeek,
sum(week = 'thirdWeek') as thirdWeek
from
(
select 'currentWeek' as week, name from currentWeek
union all
select 'lastWeek' as week, name from lastWeek
union all
select 'thirdWeek' as week, name from thirdWeek
) all_weeks
group by name
order by name;
(If you want to join the three tables instead, you'd need full outer joins, which MySQL does not support, if I remember correctly. Anyway, my advice is to change the data model.)
You can try this query:
select currweek.name, currweek.att, lastweek.att, twoWkAgo.att from
(select name, count(attendance) as att from currentWeekTable group by name) currweek,
(select name, count(attendance) as att from lastWeekTable group by name) lastweek,
(select name, count(attendance) as att from twoWeekTable group by name) twoWkAgo
where twoWkAgo.name=currWeek.name and twoWkAgo.name=lastweek.name;
Assuming your 3 attendance tables contain name as common field.

SQL into Table Multiple queries same column

I am trying to create a web based report to show the response of certain advertisements.
$sql1 = "
SELECT date
, source
, source_desc
, COUNT(ordernumber) count
, SUM(ordervalue) value
, type
FROM dailystats
WHERE client = '$client2'
AND event <> 'B02'
AND date BETWEEN '$start' AND '$end'
GROUP
BY source
ORDER
BY source;
";
This works fine for my table to show total values, but I want to break it down further. I currently have SOURCE {source}, DESCRIPTION {source_desc}, TOTAL ORDERS {count}, TOTAL ORDER VALUE {value}, as my headers which are populated by the above fields.
I want, as well as the current totals, to include further columns when the field "TYPE" is "P", "T" and "E". I want this to leave me with data to fill new headers (when I put them into the table) consisting of SOURCE, DESCRIPTION, WEB ORDERS, WEB ORDER VALUE, PHONE ORDERS, PHONE ORDER VALUE, POST ORDERS, POST ORDER VALUE, TOTAL ORDERS, TOTAL ORDER VALUE.
I need to create the data for the new headers, so WEB ORDERS will give me the total orders with the TYPE "E". On its own this would be something like COUNT(ordernumber) count where type = "E", but I need multiple of these and I cannot get it to work.
It currently looks like this :
|Source|Source Description|Total Orders|Total Order Value|
|DM1 |Daily Mail 1 |500 |5,000 |
I want to retain this information, but add in as described above, to look like this.
|Source|Source Description|Web Orders|Web Order Value|Post Orders|Post Order Value|Mail Orders|Mail Order Value|Total Orders|Total Order Value|
|DM1 |Daily Mail 1 |100 |1,000 |300 |3,000 |100 |1,000 |500 |5,000 |
I hope I have explained my problem adequately.
use group_concat(type) as type in your code.
(if it is wrong sry. pls explain it clear)
I want this to leave me with headers (when I put them into the table) of SOURCE, DESCRIPTION, WEB ORDERS, WEB ORDER VALUE, PHONE ORDERS, PHONE ORDER VALUE, POST ORDERS, POST ORDER VALUE, TOTAL ORDERS, TOTAL ORDER VALUE.
If i understand correctly you want to add headers to your result ? this should be done by:
SELECT column_name(s)
FROM table_name AS alias_name;

mysql highly selective query

I have a data set like this:
User Date Status
Eric 1/1/2015 4
Eric 2/1/2015 2
Eric 3/1/2015 4
Mike 1/1/2015 4
Mike 2/1/2015 4
Mike 3/1/2015 2
I'm trying to write a query in which I will retrieve users whose MOST RECENT transaction status is a 4. If it's not a 4 I don't want to see that user in the results. This dataset could have 2 potential results, one for Eric and one for Mike. However, Mike's most recent transaction was not a 4, therefore:
The return result would be:
User Date Status
Eric 3/1/2015 4
As this record is the only record for Eric that has a 4 as his latest transaction date.
Here's what I've tried so far:
SELECT
user, MAX(date) as dates, status
FROM
orders
GROUP BY
status,
user
This would get me to a unqiue record for every user for every status type. This would be a subquery, and the parent query would look like:
SELECT
user, dates, status
WHERE
status = 4
GROUP BY
user
However, this is clearly flawed as I don't want status = 4 records IF their most recent record is not a 4. I only want status = 4 when the latest date is a 4. Any thoughts?
SELECT user, date
, actualOrders.status
FROM (
SELECT user, MAX(date) as date
FROM orders
GROUP BY user) AS lastOrderDates
INNER JOIN orders AS actualOrders USING (user, date)
WHERE actualOrders.status = 4
;
-- Since USING is being used, there is not a need to specify source of the
-- user and date fields in the SELECT clause; however, if an ON clause was
-- used instead, either table could be used as the source of those fields.
Also, you may want to rethink the field names used if it is not too late and user and date are both found here.
SELECT user, date, status FROM
(
SELECT user, MAX(date) as date, status FROM orders GROUP BY user
)
WHERE status = 4
The easiest way is to include your order table a second time in a subquery in your from clause in order to retrieve the last date for each user. Then you can add a where clause to match the most recent date per user, and finally filter on the status.
select orders.*
from orders,
(
select ord_user, max(ord_date) ord_date
from orders
group by ord_user
) latestdate
where orders.ord_status = 4
and orders.ord_user = latestdate.ord_user
and orders.ord_date = latestdate.ord_date
Another option is to use the over partition clause:
Oracle SQL query: Retrieve latest values per group based on time
Regards,

MySQL ORDER BY Column = value AND distinct?

I'm getting grey hair by now...
I have a table like this.
ID - Place - Person
1 - London - Anna
2 - Stockholm - Johan
3 - Gothenburg - Anna
4 - London - Nils
And I want to get the result where all the different persons are included, but I want to choose which Place to order by.
For example. I want to get a list where they are ordered by LONDON and the rest will follow, but distinct on PERSON.
Output like this:
ID - Place - Person
1 - London - Anna
4 - London - Nils
2 - Stockholm - Johan
Tried this:
SELECT ID, Person
FROM users
ORDER BY FIELD(Place,'London'), Person ASC "
But it gives me:
ID - Place - Person
1 - London - Anna
4 - London - Nils
3 - Gothenburg - Anna
2 - Stockholm - Johan
And I really dont want Anna, or any person, to be in the result more then once.
This is one way to get the specified output, but this uses MySQL specific behavior which is not guaranteed:
SELECT q.ID
, q.Place
, q.Person
FROM ( SELECT IF(p.Person<=>#prev_person,0,1) AS r
, #prev_person := p.Person AS person
, p.Place
, p.ID
FROM users p
CROSS
JOIN (SELECT #prev_person := NULL) i
ORDER BY p.Person, !(p.Place<=>'London'), p.ID
) q
WHERE q.r = 1
ORDER BY !(q.Place<=>'London'), q.Person
This query uses an inline view to return all the rows in a particular order, by Person, so that all of the 'Anna' rows are together, followed by all the 'Johan' rows, etc. The set of rows for each person is ordered by, Place='London' first, then by ID.
The "trick" is to use a MySQL user variable to compare the values from the current row with values from the previous row. In this example, we're checking if the 'Person' on the current row is the same as the 'Person' on the previous row. Based on that check, we return a 1 if this is the "first" row we're processing for a a person, otherwise we return a 0.
The outermost query processes the rows from the inline view, and excludes all but the "first" row for each Person (the 0 or 1 we returned from the inline view.)
(This isn't the only way to get the resultset. But this is one way of emulating analytic functions which are available in other RDBMS.)
For comparison, in databases other than MySQL, we could use SQL something like this:
SELECT ROW_NUMBER() OVER (PARTITION BY t.Person ORDER BY
CASE WHEN t.Place='London' THEN 0 ELSE 1 END, t.ID) AS rn
, t.ID
, t.Place
, t.Person
FROM users t
WHERE rn=1
ORDER BY CASE WHEN t.Place='London' THEN 0 ELSE 1 END, t.Person
Followup
At the beginning of the answer, I referred to MySQL behavior that was not guaranteed. I was referring to the usage of MySQL User-Defined variables within a SQL statement.
Excerpts from MySQL 5.5 Reference Manual http://dev.mysql.com/doc/refman/5.5/en/user-variables.html
"As a general rule, other than in SET statements, you should never assign a value to a user variable and read the value within the same statement."
"For other statements, such as SELECT, you might get the results you expect, but this is not guaranteed."
"the order of evaluation for expressions involving user variables is undefined."
Try this:
SELECT ID, Place, Person
FROM users
GROUP BY Person
ORDER BY FIELD(Place,'London') DESC, Person ASC;
You want to use group by instead of distinct:
SELECT ID, Person
FROM users
GROUP BY ID, Person
ORDER BY MAX(FIELD(Place, 'London')), Person ASC;
The GROUP BY does the same thing as SELECT DISTINCT. But, you are allowed to mention other fields in clauses such as HAVING and ORDER BY.