Looking for latest results by using group_by - mysql

i'm trying to create an overview page for my customers and would like to show when the customer (within the last year) used a type of service (e.g. window cleaning or floor cleaning).
I tried it this way:
SELECT start, project_id, category_id, MAX(start)
FROM `time_entries`
WHERE project_id = '$project_id' AND start > '$oneyearago'
GROUP BY category_id
project_id = kind of a unique customer id
category_id = 1 for window cleaning, 2 for floor cleaning and so on
start = DATETIME when the last service started
I would like to show the LAST services, but it only shows the oldest services. What am i Doing wrong? does anyone here has a idea for me?
Thank you very much in advance.
EDIT: This is the database example
id project_id category_id start
---|------------|-----------|-------------------
1 | 1 | 1 | 2019-11-11 09:51:07
2 | 1 | 2 | 2019-11-12 09:51:07
5 | 1 | 3 | 2019-11-13 09:51:07
3 | 1 | 1 | 2020-11-11 09:51:07
4 | 1 | 2 | 2020-11-12 09:51:07
5 | 1 | 3 | 2020-11-13 09:51:07
6 | 1 | 1 | 2021-11-11 09:51:07
7 | 1 | 2 | 2021-11-12 09:51:07
I would like to see
category 1: last appointment was 2021-11-11
category 2: last appointment was 2021-11-12
category 3: last appointment was 2020-11-13

I was asking for scripts like this
CREATE TABLE time_entries (id int, project_id int, category_id int, start datetime);
INSERT INTO time_entries VALUES(1 , 1 , 1 , '2019-11-11 09:51:07'),(2 , 1 , 2 , '2019-11-12 09:51:07'), (5 , 1 , 3 , '2019-11-13 09:51:07'), (3 , 1 , 1 , '2020-11-11 09:51:07'), (4 , 1 , 2 , '2020-11-12 09:51:07'), (5 , 1 , 3 , '2020-11-13 09:51:07'), (6 , 1 , 1 , '2021-11-11 09:51:07'), (7 , 1 , 2 , '2021-11-12 09:51:07');
Now, solution to your problem. you can add date check in where clause.
SELECT T1.id, T1.start, T1.project_id, T1.category_id, T2.start
FROM time_entries T1
INNER JOIN(
SELECT category_id, MAX(start)start
FROM time_entries
WHERE project_id=1
GROUP BY category_id
)T2 ON T1.category_id=T2.category_id AND T1.start = T2.Start
ORDER BY T1.category_id

Please try below query
SELECT project_id, category_id, MAX(start) as last_datetime FROM time_entries WHERE project_id = '$project_id' GROUP BY category_id

Related

mysql group by but only group if second row is the same

im wondering what the smartest way is to group my mysql results... I have the following table structure:
- id
- userId
- status (values from 1-100)
Lets say with the following content:
1 | 1 | 10
2 | 1 | 10
3 | 1 | 15
4 | 2 | 15
5 | 3 | 10
Now I want to group all results by user but only for each status. So the results im looking for should be:
1 | 1 | 10
3 | 1 | 15
4 | 2 | 15
5 | 3 | 10
Hope you understand want im looking for...
Best
Tassilo
If you need the id, then a GROUPing query is needed; this will produce the results you shown:
SELECT MIN(id), userId, status
FROM your_table
GROUP BY userId, status
;
If you don't need the id, then GROUPing is not the best tool, use DISTINCT instead; like so:
SELECT DISTINCT userId, status
FROM your_table
;
The topic of this question say "Group only if next row is the same" in that case I would do something like this:
create table USER_(id integer, UserId integer, status integer);
insert into USER_ values(1,1,10);
insert into USER_ values(2,1,10);
insert into USER_ values(3,1,115);
insert into USER_ values(4,2,115);
insert into USER_ values(5,3,10);
insert into USER_ values(6,1,10);
select min(a.id)as id, a.userId, a.status ,count(*) from USER_ a join USER_ b
on a.userid = b.userid and a.id = b.id-1 group by a.userId,a.status;
id | userid | status | count
-----+--------+--------+-------
1 | 1 | 10 | 2
If I look at the explanation for the question here then, I would do something like this:
select min(a.id) as id, a.userId, a.status from USER_ a
group by a.userId,a.status order by a.userid,status;
id | userid | status
----+--------+--------
1 | 1 | 10
3 | 1 | 15
4 | 2 | 15
5 | 3 | 10
Please correct if I have a wrong understanding of the question

Mysql Query for date-range

I have a booking table where all the service booking list where booking details saved like this:
id user_id booking_date booking_id
1 3 2017-01-10 booking1
2 3 2017-01-11 booking1
3 3 2017-01-12 booking1
4 3 2017-01-13 booking1
5 3 2017-01-14 booking1
6 4 2017-01-19 booking2
7 4 2017-01-20 booking2
8 4 2017-01-21 booking2
9 4 2017-01-22 booking2
10 3 2017-02-14 booking3
11 3 2017-02-15 booking3
I want to get a start and end date of booking that came in a row.
like for user_id 3 has 2 date range of booking date
from `2017-01-10 to 2017-01-14`
and then after some records
from `2017-02-14 to 2017-02-15`
First of all, I don't think that getting sequences like that does make sense. ... But, ok.
To do this in one Query would be compicated with that data. So I would first add some column like "group_id" or "order_id". So you can save one ID to all orders that belong together.
Just iterate over the Table, ascending by ID and check if the next (or last) data has the same user_id.
When you do have the order_id column, you can simple
SELECT MIN(booking_date), MAX(booking_date) FROM table GROUP BY order_id
Ok, nobody says it is easy ... let's go. This is a gap and island problem. let me say it is mooooore easy to solve in postges sql
I apply mysql variables to your scenario.
I solve it on SQL Fiddle:
MySQL 5.6 Schema Setup:
create table t ( user_id int, booking_date date );
insert into t values
( 3, '2017-01-10'),
( 3, '2017-01-11'),
( 3, '2017-01-12'),
( 3, '2017-01-13'),
( 3, '2017-01-14'),
( 4, '2017-01-19'),
( 4, '2017-01-20'),
( 4, '2017-01-21'),
( 4, '2017-01-22'),
( 3, '2017-02-14'),
( 3, '2017-02-15');
Query 1:
select user_id, min(booking_date), max(booking_date)
from (
select t1.user_id,
t1.booking_date,
#g := case when(
DATE_ADD(#previous_date, INTERVAL 1 DAY) <> t1.booking_date or
#previous_user <> t1.user_id )
then t1.booking_date
else #g
end as g,
#previous_user:= t1.user_id,
#previous_date:= t1.booking_date
from t t1, ( select
#previous_user := -1,
#previous_date := STR_TO_DATE('01/01/2000', '%m/%d/%Y'),
#g:=STR_TO_DATE('01/01/2000', '%m/%d/%Y') ) x
order by user_id, booking_date
) X
group by user_id, g
Results:
| user_id | min(booking_date) | max(booking_date) |
|---------|-------------------|-------------------|
| 3 | 2017-01-10 | 2017-01-14 |
| 3 | 2017-02-14 | 2017-02-15 |
| 4 | 2017-01-19 | 2017-01-22 |
Explanation nested query figure up a group code ( g ) for each range. The external query get the max and the min for each group.

MySql order multiple columns consider multiple

id | p_id
--------------------------
1 | 0
2 | 0
3 | 1
4 | 2
5 | 0
6 | 7
7 | 1
8 | 0
This is above table data's, if i give
SELECT * from tablename order by `id` asc
it will bring the above result set
But my use case is i need to sort by both the id and p_id in a different way (i.e) i need to get result set by like below
id | p_id
--------------------------
1 | 0
3 | 1
7 | 1
6 | 7
2 | 0
4 | 2
5 | 0
8 | 0
let me explain briefly about that, p_id value 1 should be the next to the id 1 and that is arranged like above, it clearly show that p_id 1 and p_id 2 is next to the id 1 and 2 respectively and make sure that id 7 in order and id 6 next to id 7
If I understood you correctly , you want the order to be -> If P_id=0 then to order by ID , else, order by p_id.
You can achieve this by conditional ordering using CASE EXPRESSION :
SELECT *
FROM YourTable t
ORDER BY CASE WHEN t.pid = 0
THEN t.id
ELSE t.p_id
END ASC,
t.id
This should return you your expected results.
You need to know the relationship between the id's and since the 2 id blocks have different sort requirements you also need a helper column and a subquery.
create table t (id int, pid int)
insert into t
values
( 1 , 0),
( 2 , 0),
( 3 , 1),
( 4 , 2),
( 5 , 0),
( 6 , 7),
( 7 , 1),
( 8 , 0)
select s.id,s.pid
from
(
select case
when t.id in (1,3,7,6) then 1
else 2
end as ac
,
case
when t.id in (1,3,7,6) then pid
else id
end as sortcol
,
t.*
from t
) s
order by s.ac,s.sortcol
Result
id pid
1 0
3 1
7 1
6 7
2 0
4 2
5 0
8 0

MySQL : collect the sum of the associated values

I have three tables in database:
Table: article
id | code | name | quantity | stock_date
--------------------------------------------------
1 1dfod Article name 10 2016-04-01
Table: selling
id | client_id | selling_type_id | selling_date | selling_status
----------------------------------------------------------------
1 1 1 2016-04-02 1
2 1 1 2016-04-03 1
3 1 1 2016-04-04 1
Table: selling_detail
id | selling_id | article_id | quantity
-------------------------------------
1 1 1 2
2 1 1 3
3 1 1 1
4 2 1 3
5 3 1 1
at the end I would have a stock record for this article like this:
date | in_stock (item in stock) | out_stock (sum of item sold)
----------------------------------------------------------------------
2016-04-01 10 0
2016-04-02 0 6
2016-04-03 0 3
2016-04-04 0 1
All mysql queries to my knowledge do not give me this result.
Here is my code:
SELECT SUM(sd.quantity) out_stock, s.search_date, ifnull(ss.quantity, 0) in_stock
FROM selling_detail sd JOIN selling s ON (sd.selling_id = s.id)
LEFT JOIN shop_stock ss ON (ss.search_date = s.search_date) WHERE (sd.shop_stock_id = 1)
GROUP BY s.search_date;
SELECT date,SUM(in_stock) in_stock,SUM(out_stock) out_stock FROM
(
SELECT stock_date date,quantity in_stock,0 out_stock FROM article
UNION
SELECT selling_date,0,quantity FROM selling JOIN selling_detail ON selling_detail.selling_id = selling.id
) x
GROUP BY date;
As you are trying to combine similar data from two very different tables, you'll probably be staring down the barrel of a UNION ALL.
Something along these lines should get you started:
SELECT *
FROM (
SELECT a.stock_date `date`,
SUM(a.quantity) `in_stock (item in stock)`,
0 `out_stock (sum of item sold)`
FROM article a
WHERE a.id = :article_id
GROUP BY `date`
UNION ALL
SELECT s.selling_date,
0,
SUM(sd.quantity)
FROM selling s
JOIN selling_detail sd
ON sd.selling_id = s.id
AND sd.article_id = :article_id
/* WHERE s.selling_type = ??
AND s.selling_status = ?? /* If necessary */
GROUP BY `date`
) sr
ORDER BY `date`

Cumulative Sum of group count in mysql query

I have a table look like below....
ID HID Date UID
1 1 2012-01-01 1002
2 1 2012-01-24 2005
3 1 2012-02-15 5152
4 2 2012-01-01 6252
5 2 2012-01-19 10356
6 3 2013-01-06 10989
7 3 2013-03-25 25001
8 3 2014-01-14 35798
How can i group by HID, Year, Month and count(UID) and add a cumulative_sum (which is count of UID). So the final result look like this...
HID Year Month Count cumulative_sum
1 2012 01 2 2
1 2012 02 1 3
2 2012 01 2 2
3 2013 01 1 1
3 2013 03 1 2
3 2014 01 1 3
What's the best way to accomplish this using query?
I made assumptions about the original data set. You should be able to adapt this to the revised dataset - although note that the solution using variables (instead of my self-join) is faster...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(ID INT NOT NULL
,Date DATE NOT NULL
,UID INT NOT NULL PRIMARY KEY
);
INSERT INTO my_table VALUES
(1 ,'2012-01-01', 1002),
(1 ,'2012-01-24', 2005),
(1 ,'2012-02-15', 5152),
(2 ,'2012-01-01', 6252),
(2 ,'2012-01-19', 10356),
(3 ,'2013-01-06', 10989),
(3 ,'2013-03-25', 25001),
(3 ,'2014-01-14', 35798);
SELECT a.*
, SUM(b.count) cumulative
FROM
(
SELECT x.id,YEAR(date) year,MONTH(date) month, COUNT(0) count FROM my_table x GROUP BY id,year,month
) a
JOIN
(
SELECT x.id,YEAR(date) year,MONTH(date) month, COUNT(0) count FROM my_table x GROUP BY id,year,month
) b
ON b.id = a.id AND (b.year < a.year OR (b.year = a.year AND b.month <= a.month)
)
GROUP
BY a.id, a.year,a.month;
+----+------+-------+-------+------------+
| id | year | month | count | cumulative |
+----+------+-------+-------+------------+
| 1 | 2012 | 1 | 2 | 2 |
| 1 | 2012 | 2 | 1 | 3 |
| 2 | 2012 | 1 | 2 | 2 |
| 3 | 2013 | 1 | 1 | 1 |
| 3 | 2013 | 3 | 1 | 2 |
| 3 | 2014 | 1 | 1 | 3 |
+----+------+-------+-------+------------+
If you don't mind an extra column in the result, you can simplify (and accelerate) the above, as follows:
SELECT x.*
, #running:= IF(#previous=x.id,#running,0)+x.count cumulative
, #previous:=x.id
FROM
( SELECT x.id,YEAR(date) year,MONTH(date) month, COUNT(0) count FROM my_table x GROUP BY id,year,month ) x
,( SELECT #cumulative := 0,#running:=0) vals;
The code turns out kind of messy, and it reads as follows:
SELECT
HID,
strftime('%Y', `Date`) AS Year,
strftime('%m', `Date`) AS Month,
COUNT(UID) AS Count,
(SELECT
COUNT(UID)
FROM your_db A
WHERE
A.HID=B.HID
AND
(strftime('%Y', A.`Date`) < strftime('%Y', B.`Date`)
OR
(strftime('%Y', A.`Date`) = strftime('%Y', B.`Date`)
AND
strftime('%m', A.`Date`) <= strftime('%m', B.`Date`)))) AS cumulative_count
FROM your_db B
GROUP BY HID, YEAR, MONTH
Though by using views, it should become much clearer:
CREATE VIEW temp_data AS SELECT
HID,
strftime('%Y', `Date`) as Year,
strftime('%m', `Date`) as Month,
COUNT(UID) as Count
FROM your_db GROUP BY HID, YEAR, MONTH;
Then your statement will read as follows:
SELECT
HID,
Year,
Month,
`Count`,
(SELECT SUM(`Count`)
FROM temp_data A
WHERE
A.HID = B.HID
AND
(A.Year < B.Year
OR
(A.Year = B.Year
AND
A.Month <= B.Month))) AS cumulative_sum
FROM temp_data B;