mysql running difference with group by - mysql

Dataset I am experimenting has the structure as given in this SQLFiddle.
create table readings_tab (id int, site varchar(15), logged_at datetime, reading smallint);
insert into readings_tab values (1, 'A', '2017-08-21 13:22:00', 2500);
insert into readings_tab values (2, 'B', '2017-08-21 13:22:00', 1210);
insert into readings_tab values (3, 'C', '2017-08-21 13:22:00', 3500);
insert into readings_tab values (4, 'A', '2017-08-22 13:22:00', 2630);
insert into readings_tab values (5, 'B', '2017-08-22 13:22:00', 1400);
insert into readings_tab values (6, 'C', '2017-08-22 13:22:00', 3800);
insert into readings_tab values (7, 'A', '2017-08-23 13:22:00', 2700);
insert into readings_tab values (8, 'B', '2017-08-23 13:22:00', 1630);
insert into readings_tab values (9, 'C', '2017-08-23 13:22:00', 3950);
insert into readings_tab values (10, 'A', '2017-08-24 13:22:00', 2850);
insert into readings_tab values (11, 'B', '2017-08-24 13:22:00', 1700);
insert into readings_tab values (12, 'C', '2017-08-24 13:22:00', 4200);
insert into readings_tab values (13, 'A', '2017-08-25 13:22:00', 3500);
insert into readings_tab values (14, 'B', '2017-08-25 13:22:00', 2300);
insert into readings_tab values (15, 'C', '2017-08-25 13:22:00', 4700);
Current Query:
select t.rownum, t.logged_on, t.tot_reading, coalesce(t.tot_reading - t3.tot_reading, 0) AS daily_generation
from
(
select #rn:=#rn+1 AS rownum, date(t.logged_at) AS logged_on, sum(t.reading) AS tot_reading
from readings_tab t, (SELECT #rn:=0) t2
group by date(t.logged_at)
order by date(t.logged_at) desc
) t
left join
(
select #rn:=#rn+1 AS rownum, date(t.logged_at) AS logged_on, sum(t.reading) AS tot_reading
from readings_tab t, (SELECT #rn:=0) t2
group by date(t.logged_at)
order by date(t.logged_at) desc
) t3 on t.rownum = t3.rownum + 1
order by t.logged_on desc;
I am expecting below output. I don't need the formula (3500+2300+4700, etc...) in the result set. Just included it to make it understandable.
-----------------------------------------------------------------
| logged_on | tot_reading | daily_generation |
-----------------------------------------------------------------
| 2017-08-25 | (3500+2300+4700) = 10500 | (10500 - 8750) = 1750 |
| 2017-08-24 | (2850+1700+4200) = 8750 | (8750-8280) = 470 |
| 2017-08-23 | (2700+1630+3950) = 8280 | (8280-7830) = 450 |
| 2017-08-22 | (2630+1400+3800) = 7830 | (7830-7210) = 620 |
| 2017-08-21 | (2500+1210+3500) = 7210 | 0 |
-----------------------------------------------------------------
I cannot figure out why it doesn't produce expected output. Can someone please help?

If using variables make sure they are unique to each subquery else you can get incorrect results. I suggest the following adjusted query (which has some added columns to help follow what is happening):
select
t.rownum, t.logged_on, t.tot_reading
, coalesce(t.tot_reading - t3.tot_reading, 0) AS daily_generation
, t3.rownum t3_rownum
, t3.tot_reading t3_to_read
, t.tot_reading t_tot_read
from
(
select #rn:=#rn+1 AS rownum, date(t.logged_at) AS logged_on, sum(t.reading) AS tot_reading
from readings_tab t
cross join (SELECT #rn:=0) t2
group by date(t.logged_at)
order by date(t.logged_at) desc
) t
left join
(
select #rn2:=#rn2+1 AS rownum, date(t.logged_at) AS logged_on, sum(t.reading) AS tot_reading
from readings_tab t
cross join (SELECT #rn2:=0) t2
group by date(t.logged_at)
order by date(t.logged_at) desc
) t3 on t.rownum = t3.rownum + 1
order by t.logged_on desc
;
Note I also recommend using explicit CROSS JOIN syntax as it leads to easier comprehension for anyone who needs to maintain this query.
Here is the result (& also see http://sqlfiddle.com/#!9/dcb5e2/1 )
| rownum | logged_on | tot_reading | daily_generation | t3_rownum | t3_to_read | t_tot_read |
|--------|------------|-------------|------------------|-----------|------------|------------|
| 5 | 2017-08-25 | 10500 | 1750 | 4 | 8750 | 10500 |
| 4 | 2017-08-24 | 8750 | 470 | 3 | 8280 | 8750 |
| 3 | 2017-08-23 | 8280 | 450 | 2 | 7830 | 8280 |
| 2 | 2017-08-22 | 7830 | 620 | 1 | 7210 | 7830 |
| 1 | 2017-08-21 | 7210 | 0 | (null) | (null) | 7210 |

Related

SQL date difference using the same column based on conditions

I'm trying to calculate the days since the last different order so for example let's say I have the following table:
cust_id|Product_id|Order_date|
1 |a |10/02/2020|
2 |b |10/01/2020|
3 |c |09/07/2020|
4 |d |09/02/2020|
1 |a |08/29/2020|
1 |f |08/02/2020|
2 |g |07/01/2020|
3 |t |06/06/2020|
4 |j |05/08/2020|
1 |w |04/20/2020|
I want to find the difference between the most recent date and the previous date that has a product ID that doesn't match the most recent product ID.
So the output should be something like this:
cust_id|latest_Product_id|time_since_last_diff_order_days|
1 |a |30 |
2 |b |92 |
3 |c |91 |
4 |d |123 |
Here's the query that I tried to use but got an error (error code 1064)
SELECT a.cust_id, a.Product_ID as latest_Product_id, DATEDIFF(MAX(a.Order_date),MAX(b.Order_date)) as time_since_last_diff_order_days
FROM database_customers.cust_orders a
INNER JOIN
database_customers.cust_orders b
on
a.cust_id = b.cust_id
WHERE a.product_id =! b.prodcut_id;
Thank you for any help!
It isn't pretty,, but will do the job
CREATE TABLE tab1
(`cust_id` int, `Product_id` varchar(1), `Order_date` datetime)
;
INSERT INTO tab1
(`cust_id`, `Product_id`, `Order_date`)
VALUES
(1, 'a', '2020-10-02 02:00:00'),
(2, 'b', '2020-10-01 02:00:00'),
(3, 'c', '2020-09-07 02:00:00'),
(4, 'd', '2020-09-02 02:00:00'),
(1, 'a', '2020-08-29 02:00:00'),
(1, 'f', '2020-08-02 02:00:00'),
(2, 'g', '2020-07-01 02:00:00'),
(3, 't', '2020-06-06 02:00:00'),
(4, 'j', '2020-05-08 02:00:00'),
(1, 'w', '2020-04-20 02:00:00')
;
WITH CTE AS (SELECT `cust_id`, `Product_id`,`Order_date`,ROW_NUMBER() OVER(PARTITION BY `cust_id` ORDER BY `Order_date` DESC) rn
FROM tab1)
SELECT t1.`cust_id`, t1.`Product_id`, t2.time_since_last_diff_order_days
FROM
(SELECT
`cust_id`, `Product_id`
FROM
CTE
WHERE rn = 1 ) t1
JOIN
( SELECT `cust_id`,DATEDIFF(MAX(`Order_date`), MIN(`Order_date`)) time_since_last_diff_order_days
FROM CTE WHERE rn in (1,2) GROUP BY `cust_id`) t2 ON t1.cust_id = t2.cust_id
cust_id | Product_id | time_since_last_diff_order_days
------: | :--------- | ------------------------------:
1 | a | 34
2 | b | 92
3 | c | 93
4 | d | 117
db<>fiddle here
I want to find the difference between the most recent date and the previous date that has a product ID that doesn't match the most recent product ID.
You can use first_value() to get the last product and then aggregate:
select cust_id, last_product_id, max(order_date),
datediff(max(order_date), max(case when product_id <> last_product_id then order_date end)) as diff_from_last_product
from (select co.*,
first_value(product_id) over (partition by cust_id order by order_date) as last_product_id
from cust_orders co
) co
group by cust_id, last_product_id;

Combine rows/columns from two tables - JOIN clause

In the link see my SQLFIDDLE and see b
CREATE TABLE Projects
(`p_id` int, `project_title` varchar(9), `l_id` int);
INSERT INTO Projects
(`p_id`, `project_title`, `l_id`)
VALUES
(1, 'A', 6),
(2, 'B', 6),
(3, 'C', 7),
(4, 'D', 8),
(5, 'E', 9),
(6, 'F', 10);
CREATE TABLE Locations
(`l_id` int, `title` varchar(9), `parent_id` int );
INSERT INTO Locations
(`l_id`, `title`, `parent_id`)
VALUES
(1, 'Country', 0),
(2, 'District1', 1),
(3, 'District2', 1),
(4, 'District3', 1),
(5, 'District4', 1),
(6, 'Loc 5', 2),
(7, 'Loc 6', 3),
(8, 'Loc 7', 3),
(9, 'Loc 8', 4),
(10, 'Loc 9', 4),
(11, 'Loc 10', 4),
(12, 'Loc 11', 5);
I would like to achieve this:
+------+-----------+-------------+
| L_ID | Title | count P_ID |
+------+-----------+-------------+
| 2 | District1 | 2 |
| 3 | District2 | 2 |
| 4 | District3 | 2 |
| 5 | District4 | 0 |
+----+------------+------+-------+
I have tried with INNER JOIN, LEFT OUTER JOIN. All i can achieve is like below and doesnt help me:
+------+-----------+----------------------+
| L_ID | Title | parent_id | counted |
+------+-----------+------------+---------+
| 6 | Loc 5 | 2 | 2 |
| 7 | Loc 6 | 3 | 2 |
| 9 | Loc 8 | 4 | 2 |
+---- -+-----------+------------+---------+
Locations table is a nested one, if this matters. I need to count projects that are in each District and also to get District name.
I tried:
SELECT l.*, COUNT(p.l_id) AS thecounted
FROM locations l
INNER JOIN projects p ON p.l_id = l.l_id
GROUP BY l.parent_id
and
SELECT l.*, COUNT(p.l_id) AS thecounted
FROM locations l
LEFT OUTER JOIN projects p on l.l_id = p.l_id
GROUP BY l.parent_id
Consider two joins:
select d.l_id, d.title, count(p.l_id) count_p_id
from locations d
left join locations l on l.parent_id = d.l_id
left join projects p on p.l_id = l.l_id
where d.parent_id = 0
group by d.l_id, d.title
The query starts from the list of districts (d), whose parent is 0. Then, it goes down one level to the locations (l), and looks up the corresponding projects (p). The final step is aggregation.
The solution of GMB returns this 1 row
l_id title count_p_id
1 Country 0
using this script version
select d.l_id, d.title, count(p.l_id) count_p_id
from locations d
left join locations l on l.parent_id = d.l_id
left join projects p on p.l_id = l.l_id
where d.parent_id = 0
group by d.l_id, d.title
We get the desired result with the slightly corrected condition
where d.parent_id = 1
Result:
l_id title count_p_id
2 District1 2
3 District2 2
4 District3 2
5 District4 0
Sorry for posting the answer, instead of a simple comment, which would be sufficient, but don't have enough reputation credits yet.

SQL - get distinct values and its frequency count of occurring in a group

I have a table data as:
CREATE TABLE SERP (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
s_product_id INT,
search_product_result VARCHAR(255)
);
INSERT INTO SERP(s_product_id, search_product_result)
VALUES
(0, 'A'),
(0, 'B'),
(0, 'C'),
(0, 'D'),
(1, 'A'),
(1, 'E'),
(2, 'A'),
(2, 'B'),
(3, 'D'),
(3, 'E'),
(3, 'D');
The data set is as follows:
s_product_id | search_product_result
___________________________________________
0 | A
0 | B
0 | C
0 | D
-------------------------------------------
1 | A
1 | E
-------------------------------------------
2 | A
2 | B
-------------------------------------------
3 | D
3 | E
3 | D
I need to list all distinct search_product_result values and count frequencies of these values occurring in s_product_id.
Required Output result-set:
DISTINCT_SEARCH_PRODUCT | s_product_id_frequency_count
------------------------------------------------------------
A | 3
B | 2
C | 1
D | 2 [occurred twice in 3, but counted only once.]
E | 2
Here, A occurs in three s_product_id : 0, 1, 2, B in two : 0, 2, and so on.
D occurred twice in the same group 3, but is counted only once for that group.
I tried grouping by search_product_result, but this counts D twice in the same group.
select search_product_result, count(*) as Total from serp group by search_product_result
Output:
search_product_result | Total
------------------------------------
A | 3
B | 2
C | 1
D | 3 <---
B | 2
You can try below - use count(distinct s_product_id)
select search_product_result, count(distinct s_product_id) as Total
from serp group by search_product_result
use count(distinct()
select search_product_result, count(distinct s_product_id, search_product_result) as Total
from SERP
group by search_product_result
see dbfiddle

MySQL - GROUP BY clause recursively?

Under MySQL I can not group the three separate data columns via GROUP BY clause.
This sample contains four brands, each brand has 2 models and 4 versions of engines. I need to extract 4 vehicles the brand, the model and version of engines is different. A truly unique result in the 3 columns.
----------+--------+----------+
Brand | Model | Version |
----------+--------+----------+
Renault | Clio | Essence |
Citroen | C4 | GPL |
Ford | Fiesta | Gazole |
Peugeot | 206 | Electric |
----------+--------+----------+
This works 8/10.
SELECT brand, model, version
FROM cars WHERE version = (SELECT version FROM cars GROUP BY version ORDER BY RAND() LIMIT 1)
GROUP BY brand
An example of the table
CREATE TABLE IF NOT EXISTS `cars` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`brand` varchar(255) NOT NULL,
`model` varchar(255) NOT NULL,
`version` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci ROW_FORMAT=COMPRESSED;
INSERT INTO `cars` (`id`, `brand`, `model`, `version`) VALUES
(1, 'Renault', 'Clio ', 'Essence'),
(2, 'Renault', 'Clio ', 'Gazole'),
(3, 'Renault', 'Clio ', 'GPL'),
(4, 'Renault', 'Clio ', 'Electric'),
(5, 'Renault', 'Modus', 'Essence'),
(6, 'Renault', 'Modus', 'Gazole'),
(7, 'Renault', 'Modus', 'GPL'),
(8, 'Renault', 'Modus', 'Electric'),
(9, 'Peugeot', '307', 'Essence'),
(10, 'Peugeot', '307', 'Gazole'),
(11, 'Peugeot', '307', 'GPL'),
(12, 'Peugeot', '307', 'Electric'),
(13, 'Peugeot', '206', 'Essence'),
(14, 'Peugeot', '206', 'Gazole'),
(15, 'Peugeot', '206', 'GPL'),
(16, 'Peugeot', '206', 'Electric'),
(17, 'Citroen', 'C4', 'Essence'),
(18, 'Citroen', 'C4', 'Gazole'),
(19, 'Citroen', 'C4', 'GPL'),
(20, 'Citroen', 'C4', 'Electric'),
(21, 'Citroen', 'C5', 'Essence'),
(22, 'Citroen', 'C5', 'Gazole'),
(23, 'Citroen', 'C5', 'GPL'),
(24, 'Citroen', 'C5', 'Electric'),
(25, 'Ford', 'Focus', 'Essence'),
(26, 'Ford', 'Focus', 'Gazole'),
(27, 'Ford', 'Focus', 'GPL'),
(28, 'Ford', 'Focus', 'Electric'),
(29, 'Ford', 'Fiesta', 'Essence'),
(30, 'Ford', 'Fiesta', 'Gazole'),
(31, 'Ford', 'Fiesta', 'GPL'),
(32, 'Ford', 'Fiesta', 'Electric');
If you need unique/distinct set of (Brand,Model,Version) add all three column name in GROUP BY clause like this:
SELECT brand, model, version FROM cars
WHERE version = (SELECT version FROM cars GROUP BY version ORDER BY RAND() LIMIT 1)
GROUP BY brand, model, version
Here is what I was offered, it is not optimized but it works.
If someone with a suggestion I'm interested.
CREATE TABLE IF NOT EXISTS temp AS
SELECT
tb1.id AS id1,
tb1.brand AS brand1,
tb1.model AS model1,
tb1.version AS version1,
tb2.id AS id2,
tb2.brand AS brand2,
tb2.model AS model2,
tb2.version AS version2,
tb3.id AS id3,
tb3.brand AS brand3,
tb3.model AS model3,
tb3.version AS version3,
tb4.id AS id4,
tb4.brand AS brand4,
tb4.model AS model4,
tb4.version AS version4
FROM `cars` AS tb1
INNER JOIN `cars` AS tb2
ON tb2.brand != tb1.brand
AND tb2.model != tb1.model
AND tb2.version != tb1.version
AND tb2.id > tb1.id
INNER JOIN `cars` AS tb3
ON tb3.brand != tb2.brand
AND tb3.model != tb2.model
AND tb3.version != tb2.version
AND tb3.id > tb2.id
AND tb3.brand != tb1.brand
AND tb3.model != tb1.model
AND tb3.version != tb1.version
AND tb3.id > tb1.id
INNER JOIN `cars` AS tb4
ON tb4.brand != tb3.brand
AND tb4.model != tb3.model
AND tb4.version != tb3.version
AND tb4.id > tb3.id
AND tb4.brand != tb2.brand
AND tb4.model != tb2.model
AND tb4.version != tb2.version
AND tb4.id > tb2.id
AND tb4.brand != tb1.brand
AND tb4.model != tb1.model
AND tb4.version != tb1.version
AND tb4.id > tb1.id
LIMIT 1
--------------
select * from sample
--------------
+-----+---------+--------+----------+-----+---------+--------+----------+-----+---------+--------+----------+-----+--------+--------+----------+
| id1 | brand1 | model1 | version1 | id2 | brand2 | model2 | version2 | id3 | brand3 | model3 | version3 | id4 | brand4 | model4 | version4 |
+-----+---------+--------+----------+-----+---------+--------+----------+-----+---------+--------+----------+-----+--------+--------+----------+
| 1 | Renault | Clio | Essence | 10 | Peugeot | 307 | Gazole | 19 | Citroen | C4 | GPL | 28 | Ford | Focus | Electric |
+-----+---------+--------+----------+-----+---------+--------+----------+-----+---------+--------+----------+-----+--------+--------+----------+
and get the result formatter
SELECT id1 AS id,
brand1 AS brand,
model1 AS model,
version1 AS version
FROM temp
UNION
SELECT id2 AS id,
brand2 AS brand,
model2 AS model,
version2 AS version
FROM temp
UNION
SELECT id3 AS id,
brand3 AS brand,
model3 AS model,
version3 AS version
FROM temp
UNION
SELECT id4 AS id,
brand4 AS brand,
model4 AS model,
version4 AS version
FROM temp
+----+---------+-------+----------+
| id | brand | model | version |
+----+---------+-------+----------+
| 1 | Renault | Clio | Essence |
| 10 | Peugeot | 307 | Gazole |
| 19 | Citroen | C4 | GPL |
| 28 | Ford | Focus | Electric |
+----+---------+-------+----------+

single sql query to perform some group by

CREATE TABLE IF NOT EXISTS `projects` (
`idproject` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`date` datetime NOT NULL,
`status` enum('new','active','closed') NOT NULL,
`priority` enum('low','medium','high') NOT NULL,
PRIMARY KEY (`idproject`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=20
Here are some data:
INSERT INTO `projects` (`idproject`, `name`, `date`, `status`, `priority`) VALUES
(1, 'iCompany', '2011-03-23 11:41:44', 'new', 'medium'),
(2, 'John Doe & Co.', '2011-04-09 14:38:04', 'closed', 'low'),
(3, 'ACME, Inc.', '2011-05-21 11:43:11', 'active', 'high'),
(4, 'John Doe & Co.', '2011-03-28 15:19:45', 'active', 'low'),
(5, 'John Doe & Co.', '2011-03-08 15:16:32', 'new', 'low'),
(6, 'ACME, Inc.', '2011-04-05 20:58:42', 'active', 'low'),
(7, 'Mega Corp', '2011-04-21 08:08:53', 'new', 'low'),
(8, 'iCompany', '2011-04-17 08:40:36', 'active', 'medium'),
(9, 'iCompany', '2011-05-18 14:36:48', 'active', 'low'),
(10, 'John Doe & Co.', '2011-04-18 19:08:25', 'new', 'medium'),
(11, 'ACME, Inc.', '2011-05-19 13:11:04', 'active', 'low'),
(12, 'Foo Bars', '2011-03-03 17:19:29', 'new', 'high'),
(13, 'ACME, Inc.', '2011-04-23 20:42:33', 'active', 'medium'),
(14, 'Foo Bars', '2011-05-13 09:18:15', 'active', 'medium'),
(15, 'ACME, Inc.', '2011-03-20 14:37:18', 'new', 'low'),
(16, 'Foo Bars', '2011-04-18 13:46:23', 'active', 'high'),
(17, 'iCompany', '2011-05-31 07:13:32', 'closed', 'low'),
(18, 'Foo Bars', '2011-05-31 15:43:39', 'active', 'low'),
(19, 'John Doe & Co.', '2011-05-28 11:28:32', 'active', 'medium')
I'd like to have the list of all projects:
- with their latest (chronologically) status and priority,
- with the number of days between the first and latest entry (0 if there is
only one entry), you may ignore the hours,
- sorted by by priority ('high' first), then by name,
- without the projects where the latest status is 'closed' (omitted from
result).
Output should be:
+---------------+-----------+---------------+----------------+
¦name ¦total_days ¦latest_status ¦latest_priority ¦
+---------------+-----------+---------------+----------------+
¦ACME, Inc. ¦62 ¦active ¦high ¦
¦John Doe & Co. ¦81 ¦active ¦medium ¦
¦Foo Bars ¦89 ¦active ¦low ¦
¦Mega Corp ¦0 ¦new ¦low ¦
+---------------+-----------+---------------+----------------+
So far i got to write this:
SELECT name,status FROM projects group by name order by priority desc,name
please help?
SELECT *
FROM (
SELECT name,
DATEDIFF(MAX(date), MIN(date)) total_days,
(SELECT tt.status FROM projects tt
WHERE t.name = tt.name AND tt.date = MAX(t.DATE)) latest_status,
(SELECT tt.priority FROM projects tt
WHERE t.name = tt.name AND tt.date = MAX(t.DATE)) latest_priority
FROM projects t
GROUP BY name
) t
WHERE latest_status != 'closed'
ORDER BY (CASE latest_priority
WHEN 'high' THEN 0
WHEN 'medium' THEN 1
WHEN 'low' THEN 2
END), name;
total days: take the DATEDIFF of the MAX and MIN date, which will give you the number of days in between;
latest status: fetch the status for which the row's date is equal to the MAX date;
latest priority: fetch the priorityfor which the row's date is equal to the MAX date;
order by: translate each priority string to a numerical value and order by it.
Here's an sqlfiddle.
Try this: http://www.sqlfiddle.com/#!2/b3962/1
select p.name, r.total_days, p.status as latest_status, p.priority as latest_priority
from projects p
join
(
select name, max(date) as recent_date, datediff(max(date),min(date)) as total_days
from projects
group by name
)
-- recent
r on(r.name,r.recent_date) = (p.name,date)
where p.status not in ('closed')
order by
(case latest_priority
when 'high' then 0
when 'medium' then 1
when 'low' THEN 2
end), p.name
Output:
| NAME | TOTAL_DAYS | LATEST_STATUS | LATEST_PRIORITY |
-----------------------------------------------------------------
| ACME, Inc. | 62 | active | high |
| John Doe & Co. | 81 | active | medium |
| Foo Bars | 89 | active | low |
| Mega Corp | 0 | new | low |
If you want to make it more shorter(by using USING), make the alias of recent_date to date: http://www.sqlfiddle.com/#!2/b3962/2
select
p.name, r.total_days, p.status as latest_status, p.priority as latest_priority
from projects p
join
(
select name, max(date) as date, datediff(max(date),min(date)) as total_days
from projects
group by name
) r using(name,date)
where p.status not in ('closed')
order by
(case latest_priority
when 'high' then 0
when 'medium' then 1
when 'low' then 2
end), p.name
How it works
Work it from inside out. First step, find the latest:
select name, max(date) as recent_date, datediff(max(date),min(date)) as total_days
from projects
group by name
Output:
| NAME | DATE | TOTAL_DAYS |
--------------------------------------------------------------
| ACME, Inc. | May, 21 2011 11:43:11-0700 | 62 |
| Foo Bars | May, 31 2011 15:43:39-0700 | 89 |
| iCompany | May, 31 2011 07:13:32-0700 | 69 |
| John Doe & Co. | May, 28 2011 11:28:32-0700 | 81 |
| Mega Corp | April, 21 2011 08:08:53-0700 | 0 |
Final step, join the above results to main table:
select
p.name, r.total_days, p.status as latest_status, p.priority as latest_priority
from projects p
join
(
select name, max(date) as date, datediff(max(date),min(date)) as total_days
from projects
group by name
) r using(name,date)
where p.status not in ('closed')
order by
(case latest_priority
when 'high' then 0
when 'medium' then 1
when 'low' then 2
end), p.name
For overriding the ordering, use CASE statement on ORDER BY clause.
Output:
| NAME | TOTAL_DAYS | LATEST_STATUS | LATEST_PRIORITY |
-----------------------------------------------------------------
| ACME, Inc. | 62 | active | high |
| John Doe & Co. | 81 | active | medium |
| Foo Bars | 89 | active | low |
| Mega Corp | 0 | new | low |