Select latest data per group from joined tables - mysql

I have two tables like this:
survey:
survey_id | store_code | timestamp
product_stock:
survey_id | product_code | production_month | value
How can I get latest value, based on survey timestamp and grouped by store_code, product_code, and production_month?
for example if I have
survey_id | store_code | timestamp
1 store_1 2015-04-20
2 store_1 2015-04-22
3 store_2 2015-04-21
4 store_2 2015-04-22
survey_id | product_code | production_month | value
1 product_1 2 15
2 product_1 2 10
1 product_1 3 20
1 product_2 2 12
3 product_2 2 23
4 product_2 2 17
It'd return result like this
survey_id | store_code | time_stamp | product_code | production_month | value
2 store_1 2015-04-22 product_1 2 10
1 store_1 2015-04-20 product_1 3 20
1 store_1 2015-04-20 product_2 2 12
4 store_2 2015-04-22 product_2 2 17
and it needs to be as fast as possible, seeing the database is quite large in size

UPDATED - please run query again
Here is my answer:
SELECT survey.survey_id, survey.store_code, survey.timestamp, product_stock.survey_id, product_stock.product_code, product_stock.production_month, product_stock.value
FROM survey
INNER JOIN product_stock
ON survey.survey_id = product_stock.survey_id
WHERE survey.timestamp = (SELECT MAX(timestamp)
FROM survey)
GROUP BY survey.store_code,product_stock.product_code,product_stock.production_month;

Related

MySQL query SELECT multiple date brackets from table

Consider the following 2 MySQL tables:
Table - Commission
id
employee_id
from_date
to_date
orders_from
orders_to
commission
1
1
2021-05-01
2021-05-05
1
10
1
2
1
2021-05-06
2021-05-10
1
10
1
3
1
2021-05-11
2021-05-15
1
10
1
4
1
2021-05-01
2021-05-05
11
20
2
5
1
2021-05-06
2021-05-10
11
20
2
6
1
2021-05-11
2021-05-15
11
20
2
7
1
2021-05-01
2021-05-05
21
30
3
8
1
2021-05-06
2021-05-10
21
30
3
9
1
2021-05-11
2021-05-15
21
30
3
Table - Orders
id
employee_id
order_date
price
An employee will get a commission based on the number of his orders during each date bracket in the "commission" table.
So for example for the first 10(1-10) orders from May 1st till May 5th he'll get 1% for each order and then for the next 10(11-20) he'll get 2% for each of those and so on.
I'm going to have a form where the manager will be able to select 2 dates from a calendar in order to see what the employee should be paid.
I want to create a MySQL query that will give me all the date brackets from the table "commission" that include the 2 dates the manager has selected?
So lets say that we select the following period:
from 2021-05-03 to 2021-05-09
How will I get all just the rows for those dates? Which in this case would be ids:1,2,4,5,7,8.
P.S. Data and use case presented here are simplified for better readability/understanding
EDIT
After Thomas G's comment
Lets say that employee with id 1 has the following orders
| id | employee_id | order_date | price |
| :--- | :---------- | :--------- | :---- |
| 1 | 1 | 2021-05-03 | 100 |
| 2 | 1 | 2021-05-07 | 100 |
| 3 | 1 | 2021-05-13 | 100 |
Now I want to check what to pay that employee for the period 2021-05-03 - 2021-05-09.
In that period only the orders 1 and 2 are applicable to be paid.
If we check the commission table we can see that for this period we need records 1 and 2.
How can get rows 1 and 2 from the commission table, using the 2 dates provided, 2021-05-03 and 2021-05-09?

Get difference between two records

I got a User-Information table where every 24 hours a new record is added for each user. This record contains a user_id, a value (a counter) and the creation date.
TBL_EXAMPLE
ID | user_id | cnt_val | record_date
--------------------------------------------
1 | 10 | 46 | 2019-02-05 12:14:35
2 | 21 | 12 | 2019-02-05 12:14:35
3 | 32 | 453 | 2019-02-05 12:14:35
4 | 10 | 23 | 2019-02-06 16:11:21
5 | 21 | 34 | 2019-02-06 16:11:21
6 | 32 | 480 | 2019-02-06 16:11:21
7 | 10 | 31 | 2019-02-07 11:34:25
8 | 21 | 44 | 2019-02-07 11:34:25
9 | 32 | 489 | 2019-02-07 11:34:25
...
Expected Result:
User 10 Counter: 46 .. 31 --> Difference: 15
User 21 Counter: 12 .. 44 --> Difference: 32
User 32 Counter: 453.. 489 --> Difference: 36
I want to make a list of each difference for each specific user from the oldest to the newest data record in the table dynamically.
you could use inner join twice on table_exeple and a subquery for min and max date
select distinct t1.user_id, t1.cnt_va - t2.cnt_val
from (
select user_id , min(date) min_date, max(date) max_date
from TTBL_EXAMPLE
group by user_id
) tmm
inner join TTBL_EXAMPLE t2 ON t2.date = tmm.max_date
and t2.user_id = tmm.user_id
inner join TBL_EXAMPLE t1 ON t1.date = tmm.min_date
and t1.user_id = tmm.user_id

Group by date every 10 days

I have this scheme:
+----+--+--------+--------------------+
| ID | Amount | paydate |
+----+-----------+--------------------+
| 1 | 200 |2016-11-05 |
+----+-----------+--------------------+
| 2 | 3000 |2016-11-10 |
+----+-----------+--------------------+
| 3 | 2500 |2016-11-11 |
+----+-----------+--------------------+
| ID | 100 |2016-11-21 |
+----+-----------+--------------------+
| 1 | 200 |2016-11-22 |
+----+-----------+--------------------+
| 2 | 3000 |2016-11-23 |
+----+-----------+--------------------+
| 3 | 2500 |2016-11-29 |
+----+-----------+--------------------+
How can I get the total Amount grouped by every 10 days like from the first of every month to the 10th then from 11th to 20th and from 21st to the end of the month?
to be shown like this :
+-----------+------------------------+
| Amount | paydate |
+-----------+------------------------+
| 3200 |2016-11-1 to 2016-11-10 |
+-----------+------------------------+
| 2500 |2016-11-11 to 2016-11-20|
+-----------+------------------------+
| 5800 |2016-11-21 to 2016-11-31|
+-----------+------------------------+
I tried
SELECT
SUM(Amount) AS Amount,
year(Facture.paydate) AS Annee,
month(Facture.paydate) AS Mois
FROM Facture
GROUP BY year(Facture.paydate), month(serFacture.paydate)
but this does not give me the result I need.
select sum(Amount) as sum_amount
,case
when day(paydate) <= 10 then concat(DATE_FORMAT(paydate,'%Y-%m-01'),' to ',DATE_FORMAT(paydate,'%Y-%m-10'))
when day(paydate) <= 20 then concat(DATE_FORMAT(paydate,'%Y-%m-11'),' to ',DATE_FORMAT(paydate,'%Y-%m-20'))
else concat(DATE_FORMAT(paydate,'%Y-%m-21'),' to ',DATE_FORMAT(paydate,'%Y-%m-31'))
end as paydate_period
from t
group by paydate_period
;
sum_amount paydate_period
3200 2016-11-01 to 2016-11-10
2500 2016-11-11 to 2016-11-20
5800 2016-11-21 to 2016-11-31
Here is an example query:
select
case
when day(date_field) between 1 and 10 then "01 to 10"
when day(date_field) between 11 and 20 then "11 to 20"
when day(date_field) between 21 and 31 then "21 to 31"
end as the_range,
date_format(date_field, "%m%Y") as the_month,
count(*)
from
the_table
group by
the_range, the_month
order by
the_month, the_range;
You can adapt the query so you display your result the way you need.

MySql select all rows in one table based on MAX value in another table

I want to be able to get all the data from table 1 and table 3 below but in addition to this I also want to get the latest application stage from table 2. The latest application stage is determined by getting the max stage_date for each application.
Table 1: applications
id | applicant_id | col_x | col_y | col_z
-----------------------------------------
10 300 a b c
11 310 a b c
12 320 a b c
13 330 a b c
14 340 a b c
Table 2: application_progress
id | application_id | application_stage | stage_date | stage_notes
------------------------------------------------------------------
1 10 DRAFT 2013-01-01 (NULL)
2 10 APPLICATION 2013-01-14 (NULL)
3 10 PHASE1 2013-01-30 (NULL)
4 11 DRAFT 2013-01-01 (NULL)
4 12 DRAFT 2013-01-01 (NULL)
5 13 DRAFT 2013-01-01 (NULL)
6 14 DRAFT 2013-01-01 (NULL)
7 14 APPLICATION 2013-01-14 (NULL)
EDIT: third table
Table 3: applicants
id | applicant_name | applicant_address | programme_id
------------------------------------------------------
300 Applicant 1 abc 1
310 Applicant 2 xyz 2
320 Applicant 3 xyz 2
330 Applicant 4 xyz 2
340 Applicant 5 xyz 2
Returned data set
applicant_id | applicant_name | current_stage
---------------------------------------------------------
300 Applicant 1 PHASE1
310 Applicant 2 DRAFT
320 Applicant 3 DRAFT
330 Applicant 4 DRAFT
340 Applicant 5 APPLICATION
Am struggling with this one and would appreciate any help.
PS. Tried to put an example of sqlfiddle but it's down at the minute. I'll update this with the sqlfiddle when it's back up if haven't had an answer before this.
You can do this with a correlated subquery:
select a.*,
(select application_stage
from application_progress ap
where ap.application_id = a.id
order by stage_date desc
limit 1
) MostRecentStage
from applications a;
EDIT:
You can joining in the applicant data with something like this::
select a.*, aa.*,
(select application_stage
from application_progress ap
where ap.application_id = a.id
order by stage_date desc
limit 1
) MostRecentStage
from applications a join
applicant aa
on a.applicant_id = aa.id;

Select min/max from multiple items

I'll try to explain it as simple as possible:
First some database structure with dummy data.
Structure
tb_spec_fk
feature value
-----------------
1 1
1 2
1 3
1 4
1 5
2 2
2 3
3 1
3 4
4 2
4 3
4 4
5 1
5 3
5 5
6 3
6 5
tb_spec_feature
feature_id filter
------------------
1 2
2 2
3 2
4 2
5 1
6 0
tb_spec_value
value_id name
----------------
1 10
2 20
3 30
4 40
5 50
Now, what I want is the follow result
Result
feature_id min_value max_value
---------------------------------
1 10 50
2 20 30
3 10 40
4 20 40
But how?
Logic
Get from the tb_spec_feature where "filter" equals 2 the highest and lowest values which are present in the tb_spec_value table and connected together trough the tb_spec_fk table.
My attemps
A lot! But I'll spare you :)
SELECT
f.feature_id AS feature_id,
MAX(value.name) AS max_value,
MIN(value.name) AS min_value
FROM tb_spec_feature AS f
JOIN tb_spec_fk AS fk ON f.feature_id=fk.feature
JOIN tb_spec_value AS value ON fk.value=value.id
WHERE f.filter=2
GROUP BY f.feature_id
The two JOIN statements "link" the a feature to a value. GROUP BY groups all rows with the same feature id, and then you can take the min or max or any other aggregate function on those columns.
Demo
Here is how you can do it
select
tsf.feature_id,
tsvl.name as Min_Value,
tsvr.name as Max_Value
from tb_spec_feature as tsf
inner join (select feature , MIN(value) MinV,MAX(value)MaxV from tb_spec_fk group by feature order by feature)as tsfkl on tsfkl.feature = tsf.feature_id
left join tb_spec_value as tsvl on tsvl.value_id = tsfkl.MinV
left join tb_spec_value as tsvr on tsvr.value_id = tsfkl.MaxV
where tsf.filter = 2
group by tsf.feature_id
Output
feature_id | Min_Value | Max_Value
---------------------------------
1 | 10 | 50
2 | 20 | 30
3 | 10 | 40
4 | 20 | 40
Fiddle Demo