so, if i have this table:
| ID | Date | Status | Value |
| 1 | 2-2-2012 | A | 5 |
| 2 | 3-4-2012 | B | 3 |
| 1 | 5-6-2012 | C | 1 |
| 2 | 1-1-2012 | D | 4 |
and I need to get total value and "most recent" status for every IDs, how to do the query? i tried using group by , but the somehow only oldest status shown in the query result.
I need to get the data became like this:
| ID | Date | Status |sum(Value)|
| 2 | 3-4-2012 | B | 7 |
| 1 | 5-6-2012 | C | 6 |
i'm a total newbie in this SQL thing, not an IT person, just because my boss ask to extract some data from our database....
thanks in advance...
Since you have not mentioned any RDBMs, the query below works on almost all RDBMS.
This uses a subquery which separately gets the latest date (assuming that the data type of date is really stored as DATE and not as a string) for every ID. The result of the subquery is then joined back on the table itself in order to get the other columns.
SELECT a.ID, a.Date, a.Status, b.TotalSum
FROM tableName a
INNER JOIN
(
SELECT ID, MAX(date) max_date, SUM(Value) totalSum
FROM tableName
GROUP BY ID
) b ON a.ID = b.ID AND
a.date = b.max_date
SQLFiddle Demo
If you are using mysql then this will work
SELECT id,date,status,sum(value)
FROM (select * from yourTable order by DATE desc ) t
group by ID
order by ID desc
Related
I'm making a community database for a school project and have ran into an issue. I am attempting to integrate a log system but retrieve the latest non-null value from column in a table called logs and present that information on a different page. My current code (without any attempt at filtering by their rank) looks as follows:
SELECT m.MemberID, m.MemberName, o.OfficeID, o.OfficeDesignation, p.PositionAbbreviation, l.LogRank
FROM logs l
INNER JOIN (SELECT l.LogMember, MAX(l.LogDate) AS maxLogDate FROM logs l GROUP BY l.LogMember) l2
ON (l.LogMember = l2.LogMember AND l.LogDate = l2.maxLogDate)
INNER JOIN members m
ON (l.LogMember = m.MemberID)
INNER JOIN offices o
ON (l.LogOffice = o.OfficeID)
INNER JOIN positions p
ON (l.LogPosition = p.PositionID)
GROUP BY m.MemberID;
The above query returns the latest entry for each member in the logs table, but I can't figure out how to, when l.LogRank returns NULL, take the latest non-null value only for that column.
I have struggled with a variety of approaches to this problem over the past week to no avail. Any help/pointers would be appreciated.
EDIT: Sample data seen below:
+-------+-----------+---------+-----------+-------------+-----------+
| LogID | LogMember | LogRank | LogOffice | LogPosition | LogDate |
+-------+-----------+---------+-----------+-------------+-----------+
| 1 | 1 | 1 | 7 | 5 | TIMESTAMP |
+-------+-----------+---------+-----------+-------------+-----------+
| 2 | 1 | 1 | | 1 | TIMESTAMP |
+-------+-----------+---------+-----------+-------------+-----------+
| 3 | 1 | | 1 | | TIMESTAMP |
+-------+-----------+---------+-----------+-------------+-----------+
The various INT values reference IDs in the relevant other tables.
Desired Output:
+-------+-----------+---------+-------------------+-----------------+-----------+
| LogID | LogMember | LogRank | OfficeDesignation | PositionAbbrev. | LogDate |
+-------+-----------+---------+-------------------+-----------------+-----------+
| 1 | 1 | 1 | C-6 | CO | TIMESTAMP |
+-------+-----------+---------+-------------------+-----------------+-----------+
So basically I want to retrieve the MemberID, MemberName, OfficeID, OfficeDesignation, PositionAbbreviation, and LogRank from a variety of tables and get the latest non-null record for each column.
INNER JOIN (
SELECT l.LogMember, l.LogRank FROM logs l
WHERE l.LogDate=(
SELECT LogDate FROM logs
WHERE LogMember=l.LogMember
AND LogRank IS NOT NULL
ORDER BY LogDate DESC
LIMIT 1
)
) l3
ON (l.LogMember = l3.LogMember)
I have the following columns:
| order_id | client_id | order_timestamp | buyer_id | (all INTs)
It started with the easy-sounding task "Show me the buyer of the last order for each client", so basically
SELECT
client_id,
max(order_timestamp),
buyer_id
FROM table t
GROUP BY client_id;
if GROUP BY would work as one would expect/wish. I know that this is kind of a common problem, but I've never seen this case in particular where you need another value in addition to the one you're grouping by. I guess using the Window functions could help, but we're using MariaDB 10.0, so that's not really an option. I tried different subselect and joins but it always ends with the problem that I can't use the order_id to join, since I have to group by the client_id. It also came to my mind to join using the client_id AND order_timestamp but the combination is not unique in the table, since it's possible to have orders with the exact same (Unix) timestamp for one client or client/buyer combination (so yeah, this would be an edge case, I would need the buyer of the order with the higher order_id, but that's a problem for another day I guess).
If the table was filled like
| order_id | client_id | order_timestamp | buyer_id |
| 1 | 123 | 9876543 | 2 |
| 2 | 123 | 9876654 | 3 |
| 3 | 234 | 9945634 | 2 |
| 4 | 234 | 9735534 | 1 |
I would like to get
| client_id | buyer_id |
------------|----------|
| 123 | 3 |
| 234 | 2 |
Hopefully, somebody can help me, so I can go to sleep in peace tonight.
If your MariaDB version supports window functions you can use ROW_NUMBER():
select t.client_id, t.buyer_id
from (
select *,
row_number() over (partition by client_id order by order_timestamp desc, order_id desc) rn
from tablename
) t
where t.rn = 1
See the demo.
Results:
| client_id | buyer_id |
| --------- | -------- |
| 123 | 3 |
| 234 | 2 |
Without window functions use NOT EXISTS:
select t.client_id, t.buyer_id
from tablename t
where not exists (
select 1 from tablename
where client_id = t.client_id
and (
order_timestamp > t.order_timestamp
or (order_timestamp = t.order_timestamp and order_id > t.order_id)
)
)
If you use max(field), it will pickup the first column of the group condition. In your case first occuring client_id per group which is not what you want.
Try this.
select client_id, order_timestamp, buyer_id from t
where order_timestamp=
(select max(ot) from t as tcopy where tcopy.client_id= t.client_id )
group by client_id;
I'm trying for too long to figure out how to write a mysql query to retrieve everything from a user, for each user, where its login date is the latest. It should work as the following:
+----+------+------------+---------+---------+
| ID | Name | Date | ColumnA | ColumnB |
+----+------+------------+---------+---------+
| 1 | John | 10/12/2019 | x | x |
| 2 | John | 08/12/2019 | x | x |
| 3 | Jane | 07/12/2019 | x | x |
| 4 | John | 03/12/2019 | x | x |
| 5 | Jane | 01/12/2019 | x | x |
+----+------+------------+---------+---------+
The desired output would be
+----+------+------------+---------+---------+
| ID | Name | Date | ColumnA | ColumnB |
+----+------+------------+---------+---------+
| 1 | John | 10/12/2019 | x | x |
| 3 | Jane | 07/12/2019 | x | x |
+----+------+------------+---------+---------+
Does anyone have an idea how to do this with a single query? It seems to be simple, and probably it is, but I can't figure it out.
A simple method is to use a correlated subquery in the where clause:
select t.*
from t
where t.date = (select max(t2.date) from t t2 where t2.name = t.name);
If date can be repeated, then the above will return multiple rows for a given user. In that case, use the unique id instead, in this way:
select t.*
from t
where t.id = (select t2.id
from t t2
where t2.name = t.name
order by t2.date desc -- might want "id desc" or "id asc" here as well
limit 1
);
This is a perfect case for Scalar-Aggregate Comparison, which will allow you to select correlated data from aggregates without the need for a correlated subquery.
SELECT
Name,
MAX(Date) AS Date,
SUBSTRING(MAX(CONCAT(Date, ColumnA)), 11) AS ColumnA,
SUBSTRING(MAX(CONCAT(Date, ColumnB)), 11) AS ColumnB
FROM TableName
GROUP BY Name;
One note is that you'll want to ensure that CONCAT(Date, ColumnA) formats the date in ISO-8601 format (YYYY-MM-DD) so that it maintains alphabetical ordinality.
If not, you may need to add a DATE_FORMAT to the query:
SELECT
Name,
MAX(Date) AS Date,
SUBSTRING(MAX(CONCAT(DATE_FORMAT(Date, '%Y-%m-%d'), ColumnA)), 11) AS ColumnA,
SUBSTRING(MAX(CONCAT(DATE_FORMAT(Date, '%Y-%m-%d'), ColumnB)), 11) AS ColumnB
FROM TableName
GROUP BY Name;
You can read more about the technique here: https://www.stevenmoseley.com/high-performance-correlated-aggregate-sql-queries-without-ctes
For every ID_Number, there is a bill_date and then two types of bills that happen. I want to return the latest date (max date) for each ID number and then add together the two types of bill amounts. So, based on the table below, it should return:
| 1 | 201604 | 10.00 | |
| 2 | 201701 | 28.00 | |
tbl_charges
+-----------+-----------+-----------+--------+
| ID_Number | Bill_Date | Bill_Type | Amount |
+-----------+-----------+-----------+--------+
| 1 | 201601 | A | 5.00 |
| 1 | 201601 | B | 7.00 |
| 1 | 201604 | A | 4.00 |
| 1 | 201604 | B | 6.00 |
| 2 | 201701 | A | 15.00 |
| 2 | 201701 | B | 13.00 |
+-----------+-----------+-----------+--------+
Then, if possible, I want to be able to do this in a join in another query, using ID_Number as the column for the join. Would that change the query here?
Note: I am initially only wanting to run the query for about 200 distinct ID_Numbers out of about 10 million. I will be adding an 'IN' clause for those IDs. When I do the join for the final product, I will need to know how to get those latest dates out of all the other join possibilities. (ie, how do I get ID_Number 1 to join with 201604 and not 201601?)
I would use NOT EXISTS and GROUP BY
select, t1.id_number, max(t1.bill_date), sum(t1.amount)
from tbl_charges t1
where not exists (
select 1
from tbl_charges t2
where t1.id_number = t2.id_number and
t1.bill_date < t2.bill_date
)
group by t1.id_number
the NOT EXISTS filter out the irrelevant rows and GROUP BY do the sum.
I would be inclined to filter in the where:
select id_number, sum(c.amount)
from tbl_charges c
where c.date = (select max(c2.date)
from tbl_charges c2
where c2.id_number = c.id_number and c2.bill_type = c.bill_type
)
group by id_number;
Or, another fun way is to use in with tuples:
select id_number, sum(c.amount)
from tbl_charges c
where (c.id_number, c.bill_type, c.date) in
(select c2.id_number, c2.bill_type, max(c2.date)
from tbl_charges c2
group by c2.id_number, c2.bill_type
)
group by id_number;
I know that the title sounds horrible but I have no idea how to summarize it better. I'm pretty sure that somebody had the same problem before but I couldn't find anything. RDBMS: MySQL.
Problem:
I have the following (simplified) table:
+------+------------+---------------------------------+
| name | date | score |
+------+------------+---------------------------------+
| A | 01.01.2015 | 1 |
| A | 01.02.2015 | 3 |
| A | 01.03.2015 | 4 |
| B | 01.01.2015 | 3 |
| B | 01.02.2015 | 4 |
| B | 01.03.2015 | 5 |
| C | 01.01.2015 | 1 |
| C | 01.02.2015 | 2 |
| C | 01.03.2015 | 3 |
+------+------------+---------------------------------+
There is no unique constraint or PK defined.
The table represents a highscore of a game. Every day the score of all players are inserted with values that are: name, points, now(),...
The data represent a snapshot of the score of each player at a specific time.
I want the most recent entry for each user only but only for the highest X players. So the result should look like
+------+------------+---------------------------------+
| name | date | score |
+------+------------+---------------------------------+
| A | 01.03.2015 | 4 |
| B | 01.03.2015 | 5 |
+------+------------+---------------------------------+
C doesn't appear since he's not in the top 2 (by score)
A appears with the most recent row (by date)
B appears, like A, with the most recent row (by date) and because he is in the top 2
I hope it becomes clear what I mean.
Thanks in advance!
I understand that what you need is to first select the X players who've gotten the highest score and then get their latest performance. In this case, you should do this:
SELECT *
FROM tablename t
JOIN
(
SELECT t.name, max(t.date) as max_date
FROM tablename t
JOIN
(
SELECT name
FROM
(
SELECT name, max(score) as max_score
FROM table_name
GROUP BY name
) all_highscores
ORDER BY max_score DESC
LIMIT X
) top_scores
ON top_scores.name = t.name
GROUP BY t.name
) top_last
on t.name = top_last.name
and t.date = top_last.date;