Happy Friday All, I have something I can not get sorted. I have asked before for support and found it was the best thing I could do :) So, I want to calculate number of open items based on two dates, open and close. All the data will be counted in t2 and the dates will go from t1 (that stores a lot of dates and hence I use SELECT DISTINCT)
So, the tables are as follows:
CREATE TABLE t1
(
ID int (10),
Date1 date);
insert into T1 values
( 1, '2018-12-17'),
( 2, '2018-12-18'),
( 3, '2018-12-19'),
( 4, '2018-12-19'),
( 5, '2018-12-19'),
( 6, '2018-12-20'),
( 7, '2018-12-20'),
( 8, '2018-12-21'),
( 9, '2018-12-22'),
(10, '2018-12-23'),
(11, '2018-12-24'),
(12, '2018-12-25'),
(13, '2018-12-26'),
(14, '2018-12-27'),
(15, '2018-12-28');
CREATE TABLE t2
(
ID int (10),
Open_Date date,
Close_Date date);
insert into t2 values
( 1, '2018-12-17', '2018-12-18'),
( 2, '2018-12-18', '2018-12-18'),
( 3, '2018-12-18', '2018-12-18'),
( 4, '2018-12-19', '2018-12-20'),
( 5, '2018-12-19', '2018-12-21'),
( 6, '2018-12-20', '2018-12-22'),
( 7, '2018-12-20', '2018-12-22'),
( 8, '2018-12-21', '2018-12-25'),
( 9, '2018-12-22', '2018-12-26'),
(10, '2018-12-23', '2018-12-27');
This is the outcome I want:
+------------+------------+
| Date | Count_open |
+------------+------------+
| 17/12/2018 | 1 |
| 18/12/2018 | 3 |
| 19/12/2018 | 2 |
| 20/12/2018 | 3 |
| 21/12/2018 | 4 |
| 22/12/2018 | 4 |
| 23/12/2018 | 3 |
| 23/12/2018 | 0 |
| 25/12/2018 | 0 |
| 27/12/2018 | 0 |
| 27/12/2018 | 0 |
| 28/12/2018 | 0 |
+------------+------------+
I have a total black out with the code and need your help.
Maybe this is what you are looking for?
select
x.Date1 as 'Date',
count(distinct t2.id) as 'Count_open'
from (select distinct Date1 from t1) x
left join t2 on x.Date1 between t2.Open_Date and t2.Close_Date
group by x.Date1
order by x.Date1
Result:
Date Count_open
---------- ----------
2018-12-17 1
2018-12-18 3
2018-12-19 2
2018-12-20 4
2018-12-21 4
2018-12-22 4
2018-12-23 3
2018-12-24 3
2018-12-25 3
2018-12-26 2
2018-12-27 1
2018-12-28 0
Related
I would like to display a players current score as well as how many points they have gained within a selected time frame.
I have 2 tables
skills table
+----+---------+---------------------+
| id | name | created_at |
+----+---------+---------------------+
| 1 | skill 1 | 2020-06-05 00:00:00 |
| 2 | skill 2 | 2020-06-05 00:00:00 |
| 3 | skill 3 | 2020-06-05 00:00:00 |
+----+---------+---------------------+
scores table
+----+-----------+----------+-------+---------------------+
| id | player_id | skill_id | score | created_at |
+----+-----------+----------+-------+---------------------+
| 1 | 1 | 1 | 5 | 2020-06-06 00:00:00 |
| 2 | 1 | 1 | 10 | 2020-07-06 00:00:00 |
| 3 | 1 | 2 | 1 | 2020-07-06 00:00:00 |
| 4 | 2 | 1 | 11 | 2020-07-06 00:00:00 |
| 5 | 1 | 1 | 13 | 2020-07-07 00:00:00 |
| 6 | 1 | 2 | 10 | 2020-07-07 00:00:00 |
| 7 | 2 | 1 | 12 | 2020-07-07 00:00:00 |
| 8 | 1 | 1 | 20 | 2020-07-08 00:00:00 |
| 9 | 1 | 2 | 15 | 2020-07-08 00:00:00 |
| 10 | 2 | 1 | 17 | 2020-07-08 00:00:00 |
+----+-----------+----------+-------+---------------------+
my expected results are:-
24 hour query
+-----------+---------+-------+------+
| player_id | name | score | gain |
+-----------+---------+-------+------+
| 1 | skill 1 | 20 | 7 |
| 1 | skill 2 | 15 | 5 |
+-----------+---------+-------+------+
7 day query
+-----------+---------+-------+------+
| player_id | name | score | gain |
+-----------+---------+-------+------+
| 1 | skill 1 | 20 | 10 |
| 1 | skill 2 | 15 | 14 |
+-----------+---------+-------+------+
31 day query
+-----------+---------+-------+------+
| player_id | name | score | gain |
+-----------+---------+-------+------+
| 1 | skill 1 | 20 | 15 |
| 1 | skill 2 | 15 | 14 |
+-----------+---------+-------+------+
so far I have the following, but all this does is return the last 2 records for each skill, I am struggling to calculate the gains and the different time frames
SELECT player_id, skill_id, name, score
FROM (SELECT player_id, skill_id, name, score,
#skill_count := IF(#current_skill = skill_id, #skill_count + 1, 1) AS skill_count,
#current_skill := skill_id
FROM skill_scores
INNER JOIN skills
ON skill_id = skills.id
WHERE player_id = 1
ORDER BY skill_id, score DESC
) counted
WHERE skill_count <= 2
I would like some help figuring out the query I need to build to get the desired results, or is it best to do this with php instead of in the db?
EDIT:-
MYSQL 8.0.20 dummy data id's are primary_key auto increment but I didnt ad that for simplicity:-
CREATE TABLE skills
(
id bigint,
name VARCHAR(80)
);
CREATE TABLE skill_scores
(
id bigint,
player_id bigint,
skill_id bigint,
score bigint,
created_at timestamp
);
INSERT INTO skills VALUES (1, 'skill 1');
INSERT INTO skills VALUES (2, 'skill 2');
INSERT INTO skills VALUES (3, 'skill 3');
INSERT INTO skill_scores VALUES (1, 1, 1 , 5, '2020-06-06 00:00:00');
INSERT INTO skill_scores VALUES (2, 1, 1 , 10, '2020-07-06 00:00:00');
INSERT INTO skill_scores VALUES (3, 1, 2 , 1, '2020-07-06 00:00:00');
INSERT INTO skill_scores VALUES (4, 2, 1 , 11, '2020-07-06 00:00:00');
INSERT INTO skill_scores VALUES (5, 1, 1 , 13, '2020-07-07 00:00:00');
INSERT INTO skill_scores VALUES (6, 1, 2 , 10, '2020-07-07 00:00:00');
INSERT INTO skill_scores VALUES (7, 2, 1 , 12, '2020-07-07 00:00:00');
INSERT INTO skill_scores VALUES (8, 1, 1 , 20, '2020-07-08 00:00:00');
INSERT INTO skill_scores VALUES (9, 1, 2 , 15, '2020-07-08 00:00:00');
INSERT INTO skill_scores VALUES (10, 2, 1 , 17, '2020-07-08 00:00:00');
WITH cte AS (
SELECT id, player_id, skill_id,
FIRST_VALUE(score) OVER (PARTITION BY player_id, skill_id ORDER BY created_at DESC) score,
FIRST_VALUE(score) OVER (PARTITION BY player_id, skill_id ORDER BY created_at DESC) - FIRST_VALUE(score) OVER (PARTITION BY player_id, skill_id ORDER BY created_at ASC) gain,
ROW_NUMBER() OVER (PARTITION BY player_id, skill_id ORDER BY created_at DESC) rn
FROM skill_scores
WHERE created_at BETWEEN #current_date - INTERVAL #interval DAY AND #current_date
)
SELECT cte.player_id, skills.name, cte.score, cte.gain
FROM cte
JOIN skills ON skills.id = cte.skill_id
WHERE rn = 1
ORDER BY player_id, name;
fiddle
Ps. I don't understand where gain=15 is taken for 31-day period - the difference between '2020-07-08 00:00:00' and '2020-06-06 00:00:00' is 32 days.
Well i think you need a (temporary) table for this. I will call it "player_skill_gains". Its basically the players skills ordered by created_at and with an auto_incremented id:
CREATE TABLE player_skill_gains
(`id` int PRIMARY KEY AUTO_INCREMENT NOT NULL
, `player_id` int
, skill_id int
, score int
, created_at date)
;
INSERT INTO player_skill_gains(player_id, skill_id, score, created_at)
SELECT player_skills.player_id AS player_id
, player_skills.skill_id
, SUM(player_skills.score) AS score
, player_skills.created_at
FROM player_skills
GROUP BY player_skills.id, player_skills.skill_id, player_skills.created_at
ORDER BY player_skills.player_id, player_skills.skill_id, player_skills.created_at ASC;
Using this table we can relatively easily select the last skill for each row (id-1). Using this we can calculate the gains:
SELECT player_skill_gains.player_id, skills.name, player_skill_gains.score
, player_skill_gains.score - IFNULL(bef.score,0) AS gain
, player_skill_gains.created_at
FROM player_skill_gains
INNER JOIN skills ON player_skill_gains.skill_id = skills.id
LEFT JOIN player_skill_gains AS bef ON (player_skill_gains.id - 1) = bef.id
AND player_skill_gains.player_id = bef.player_id
AND player_skill_gains.skill_id = bef.skill_id
For the different queries you want to have (24 hours, 7 days, etc.) you just have to specify the needed where-part for the query.
You can see all this in action here: http://sqlfiddle.com/#!9/1571a8/11/0
i have table like this with mysql version 5.7
CREATE TABLE order_match (
ID INT,
user_id INT,
createdAt DATE,
status_id INT,
quantity INT
);
INSERT INTO order_match VALUES
(1, 12, '2020-01-01', 4, 1),
(2, 12, '2020-01-03', 7, 1),
(3, 12, '2020-01-06', 7, 2),
(4, 13, '2020-01-02', 5, 2),
(5, 13, '2020-01-03', 6, 1),
(6, 14, '2020-03-03', 8, 0.5),
(7, 13, '2020-03-04', 4, 1),
(8, 15, '2020-04-04', 7, 3),
(9, 14, '2020-03-02', 7, 2),
(10, 14, '2020-03-10', 5, 4),
(11, 13, '2020-04-10', 8, 3),
(12, 13, '2020-04-11', 8, 2),
(13, 16, '2020-04-15', 8, 3);
select * from order_match
order by createdAt;
the output just like this
+---------+---------+------------+-----------+----------+
| ID | user_id | createdAt | status_id | quantity |
+---------+---------+------------+-----------+----------+
| 1 | 12 | 2020-01-01 | 4 | 1 |
| 4 | 13 | 2020-01-02 | 5 | 2 |
| 2 | 12 | 2020-01-03 | 7 | 1 |
| 5 | 13 | 2020-01-03 | 6 | 1 |
| 3 | 12 | 2020-01-06 | 7 | 2 |
| 9 | 14 | 2020-03-02 | 7 | 2 |
| 6 | 14 | 2020-03-03 | 8 | 1 |
| 7 | 13 | 2020-03-04 | 4 | 1 |
| 10 | 14 | 2020-03-10 | 5 | 4 |
| 8 | 15 | 2020-04-04 | 7 | 3 |
| 11 | 13 | 2020-04-10 | 8 | 3 |
| 12 | 13 | 2020-04-11 | 8 | 2 |
| 13 | 16 | 2020-04-15 | 8 | 3 |
| 13 rows | | | | |
+---------+---------+------------+-----------+----------+
with ID as the id of transaction, user_id as the buyer who doing transaction, createdAt as the date transaction happen, status_id as the status of transaction (which 4, 5, 6, 8 as the approval transaction) and quantity as the amount of quantity of every transaction
this is the fiddle
so i want to find out the statistic of how many transaction, total amount of quantity, and total frequency of unique user between 2020-03-01 until 2020-04-01, unique user is the user who doing his first approval transaction before 2020-03-01 and at least doing 1 approval transaction in between 2020-03-01 until 2020-04-01, based on the table i made the expected result just like this
+------------+------------------+-----------------+
| count user | total_order (kg) | total_order (x) |
+------------+------------------+-----------------+
| 1 | 1 | 1 |
+------------+------------------+-----------------+
explanation : as we know the user who become unique user in between 2020-03-01 until 2020-04-01 are user_id 13, because he doing his first approval transaction on 2020-01-02 (before 2020-03-01) and then doing his approval transaction at least one time on 2020-03-01 until 2020-04-01, on time range, user_id 13 (count user) doing 1 transaction (total_order (x)) and the amount are 1 kg (total_order (kg )
i've doing this syntax
select
count(distinct om.user_id) as count,
sum(om.quantity) as total_order_kg,
count(om.id) as order_x
from (select count(xx.count_) as count_
from (select count(user_id) as count_ from order_match
where status_Id in (4, 5, 6, 8)
group by user_id
) xx
) x1,
(select user_id
from order_match
group by user_id
) yy,
order_match om
where yy.user_id = om.user_id and
status_id in (4, 5, 6, 8)
and om.createdAt < '2020-03-01'
and EXISTS (select 1 from order_match om2
where om.user_id = om2.user_id
and status_id in (4, 5, 6, 8)
and om2.createdAt >= '2020-03-01'
and om2.createdAt <= '2020-04-01');
but idk why the result like this
+------------+------------------+-----------------+
| count user | total_order (kg) | total_order (x) |
+------------+------------------+-----------------+
| 1 | 3 | 2 |
+------------+------------------+-----------------+
THE FIDDLE
-- separate users statistic
SELECT user_id,
SUM(quantity * (createdAt >= #start)) total_order_kg,
SUM(createdAt >= #start) order_x
FROM order_match
WHERE createdAt <= #finish
GROUP BY user_id
HAVING SUM(createdAt >= #start)
AND SUM(createdAt >= #start) < COUNT(createdAt);
-- overall statistic
SELECT COUNT(*) users_count,
SUM(order_kg) total_order_kg,
SUM(order_count) total_order_count
FROM ( SELECT user_id,
SUM(quantity * (createdAt >= #start)) order_kg,
SUM(createdAt >= #start) order_count
FROM order_match
WHERE createdAt <= #finish
GROUP BY user_id
HAVING SUM(createdAt >= #start)
AND SUM(createdAt >= #start) < COUNT(createdAt) ) totals;
fiddle
'why the result like this' - you are using comma joins so are starting from a cartesian product you can see what is happening if you substitute the aggregations for actual values for example
select
om.user_id,
om.quantity,
om.id,
x1.count_,
yy.user_id
from (select count(xx.count_) as count_
from (select count(user_id) as count_ from t
where status_Id in (4, 5, 6, 8)
group by user_id
) xx
) x1,
(select user_id
from t
group by user_id
) yy,
t om
where yy.user_id = om.user_id and
status_id in (4, 5, 6, 8)
and om.createdAt < '2020-03-01'
and EXISTS (select 1 from t om2
where om.user_id = om2.user_id
and status_id in (4, 5, 6, 8)
and om2.createdAt >= '2020-03-01'
and om2.createdAt <= '2020-04-01');
Where t is my table name and a copy of order_match.
If you run this query without the where clause then you get 65 rows returned, if you run it with the where clause but not the exists check you get 3 rows returned if you run it in it's entirety you get
---------+----------+------+--------+---------+
| user_id | quantity | id | count_ | user_id |
+---------+----------+------+--------+---------+
| 13 | 2 | 4 | 4 | 13 |
| 13 | 1 | 5 | 4 | 13 |
+---------+----------+------+--------+---------+
2 rows in set (0.002 sec)
Which when aggregated produces the result you get from your query.
NB group by without any aggregation functions is just wrong.
In MYSQL there are 2 columns in table column A and column B and if in column A continuously comes one 10th time and in column B 11th time comes true(B can be 1 or 0 between these 10 times ) so I want that column id of B.
+----+---+---+
| id | A | B |
+----+---+---+
| 1 | 1 | 0 |
| 2 | 0 | 1 |
| 3 | 1 | 0 |
| 4 | 1 | 0 |
| 5 | 1 | 0 |
| 6 | 1 | 1 |
| 7 | 1 | 0 |
| 8 | 1 | 1 |
| 9 | 1 | 1 |
| 10 | 1 | 0 |
| 11 | 1 | 1 |
| 12 | 1 | 0 |
| 13 | 0 | 1 |
+----+---+---+
I need this (column B id) (Where Column A continuously come 1 (10 times) and Column B (11th id after contenious 10 time 1 in column A )
You could use a running total in a sub query to help you with this on versions prior to mysql 8.0
drop table if exists t;
create table t
(id int,A int,B int);
insert into t values
(1, 1 ,0),
(2, 0 ,1),
(3, 1 ,0),
(4, 1 ,0),
(5, 1 ,0),
(6, 1 ,1),
(7, 1 ,0),
(8, 1 ,1),
(9, 1 ,1),
(10, 1 ,0),
(11, 1 ,1),
(12, 1 ,0),
(13, 1 ,1),
(14, 1 ,1),
(15, 1 ,1),
(16, 0 ,1);
select t1.id,t1.a,t1.b
from
(
select t.*,
if(t.a = 1, #rt:=#rt+1,#rt:=0) rt
from t
cross join (select #rt:=0) r
order by t.id
) t1
where t1.rt >= 10;
+------+------+------+
| id | a | b |
+------+------+------+
| 12 | 1 | 0 |
| 13 | 1 | 1 |
| 14 | 1 | 1 |
| 15 | 1 | 1 |
+------+------+------+
4 rows in set (0.00 sec)
This is a complicated one. Using window functions available in MySQL 8.0, I would proceed in 3 steps:
first compute row numbers in the overall group and in groups of A values
then do a cumulative sum of A values within groups of consecutive A values (using the difference between the 2 above groups), while using LEAD() to recover the id and B value of the next record
finally, filter on the record whose cumulative SUM is 10 and whose next B value is 1; the id of the next record is what you are looking for
Query:
SELECT leadID id
FROM (
SELECT
id,
SUM(A) OVER(PARTITION BY rn1 - rn2 ORDER BY id) sm,
LEAD(id) OVER(ORDER BY id) leadID,
LEAD(B) OVER(ORDER BY id) leadB
FROM (
SELECT
id,
A,
B,
ROW_NUMBER() OVER(ORDER BY id) rn1,
ROW_NUMBER() OVER(PARTITION BY A ORDER BY id) rn2
FROM mytable
) x
) x
WHERE sm = 10 AND leadB = 1
This demo on DB Fiddle with your sample data yields:
| id |
| --- |
| 13 |
I want to use mysql to traverse all the goods_id in the goods table, and then query the sum of each row in the order_goods table based on all goods_id.Can you solve this problem?
1.Create goods table and insert table
CREATE TABLE `goods` (
`goods_id` int(11) NOT NULL,
`goods_name` varchar(255) NOT NULL,
PRIMARY KEY (`goods_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `goods` (`goods_id`, `goods_name`) VALUES
(1, 'Apple'),
(2, 'Xiaomi'),
(3, 'Huawei');
2.Create order_goods and insert table
CREATE TABLE `order_goods` (
`id` int(11) NOT NULL,
`order_id` int(11) NOT NULL,
`goods_id` int(11) NOT NULL,
`goods_name` varchar(255) NOT NULL,
`goods_num` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `order_goods` (`id`, `order_id`, `goods_id`, `goods_name`,
`goods_num`) VALUES
(1, 1, 1, 'iPhone X', 2),
(2, 2, 1, 'iPhone 8 plus', 1),
(3, 3, 2, 'Y69A', 1),
(4, 4, 2, 'X21', 3),
(5, 5, 3, 'nova 3', 1),
(6, 6, 3, 'P20 Pro', 3),
(7, 7, 3, 'Mate 10 Pro', 5);
3.Query the goods table
mysql> select * from goods;
+----------+------------+
| goods_id | goods_name |
+----------+------------+
| 1 | Apple |
| 2 | Xiaomi |
| 3 | Huawei |
+----------+------------+
3 rows in set (0.00 sec)
4.Query the order_goods table
mysql> select * from order_goods;
+----+----------+----------+---------------+-----------+
| id | order_id | goods_id | goods_name | goods_num |
+----+----------+----------+---------------+-----------+
| 1 | 1 | 1 | iPhone X | 2 |
| 2 | 2 | 1 | iPhone 8 plus | 1 |
| 3 | 3 | 2 | Y69A | 1 |
| 4 | 4 | 2 | X21 | 3 |
| 5 | 5 | 3 | nova 3 | 1 |
| 6 | 6 | 3 | P20 Pro | 3 |
| 7 | 7 | 3 | Mate 10 Pro | 5 |
+----+----------+----------+---------------+-----------+
7 rows in set (0.00 sec)
5.I want to try to get this effect!
+----+----------+----------+---------------+
| id | goods_id | goods_name | num |
+----+----------+----------+---------------+
| 1 | 1 | Apple | 3 |
| 2 | 2 | Xiaomi | 4 |
| 3 | 3 | Huawei | 9 |
+----+----------+----------+---------------+
For example, write sum(g.goods_num) as num
How to write the sql statement above?
X is the query which u do group by to have SUM()
Then u join it with goods to have the name and id and whatever u need from this table
This might be better with performance to do the group by first
WITH X AS
(
SELECT goods_id,SUM(goods_num) AS num
FROM order_goods
GROUP BY goods_id
)
SELECT G.goods_name , X.num
FROM X
INNER JOIN goods G ON G.goods_id = X.goods_id
No WITH clause so bring your join to your query
like this:
SELECT goods_id,SUM(goods_num) AS num
FROM order_goods OG
INNER JOIN goods G ON G.goods_id = OG.goods_id
GROUP BY OG.goods_id -- or G.goods_name
Firstly, do a INNER JOIN between the two tables, using goods_id.
Then, do a grouping of goods_id using GROUP BY clause.
Eventually, using aggregation function SUM function, get the desired sum value and Alias it as num.
Try the following query:
SELECT g.goods_id,
g.goods_name,
SUM(og.goods_num) AS num
FROM goods g
JOIN order_goods og ON og.goods_id = g.goods_id
GROUP BY g.goods_id, g.goods_name
Use inner join and aggregation with group by:
http://sqlfiddle.com/#!9/ae4fd9/3
select go.goods_id,g.goods_name,sum(goods_num) as num
from goods g inner join order_goods go
on g.goods_id=go.goods_id
group by g.goods_name,go.goods_id
Output:
goods_id goods_name num
1 Apple 3
3 Huawei 9
2 Xiaomi 4
I have a big trouble to find a correct way to select a column from another table, and show one results that would contain two tables in the same time.
First table:
id | times | project_id |
12 | 12.24 | 40 |
13 | 13.22 | 40 |
14 | 13.22 | 20 |
15 | 12.22 | 20 |
16 | 13.30 | 40 |
Second table:
id | times | project_id |
32 | 22.24 | 40 |
33 | 23.22 | 40 |
34 | 23.22 | 70 |
35 | 22.22 | 70 |
36 | 23.30 | 40 |
I expect to select all the times from the first table for project_id =40, and join to this times from the second table for the same project_id =40.
The results should be like this below:
id | time | time | project_id |
12 | 12.24 | 22.24 | 40 |
13 | 13.22 | 23.22 | 40 |
16 | 13.30 | 23.30 | 40 |
You need to use UNION ALL between those 2 tables otherwise you will get incorrect results. Once you have all the rows together then you can use variables to carry over "previous values" such as shown below and demonstrated at this SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE Table1
(`id` int, `times` decimal(6,2), `project_id` int)
;
INSERT INTO Table1
(`id`, `times`, `project_id`)
VALUES
(12, 12.24, 40),
(13, 13.22, 40),
(14, 13.22, 20),
(15, 12.22, 20),
(16, 13.30, 40)
;
CREATE TABLE Table2
(`id` int, `times` decimal(6,2), `project_id` int)
;
INSERT INTO Table2
(`id`, `times`, `project_id`)
VALUES
(32, 22.24, 40),
(33, 23.22, 40),
(34, 23.22, 70),
(35, 22.22, 70),
(36, 23.30, 40)
;
Query 1:
select
project_id, id, prev_time, times
from (
select
#row_num :=IF(#prev_value=d.project_id,#row_num+1,1) AS RowNumber
, d.*
, IF(#row_num %2 = 0, #prev_time, '') prev_time
, #prev_value := d.project_id
, #prev_time := times
from (
select `id`, `times`, `project_id` from Table1
union all
select `id`, `times`, `project_id` from Table2
) d
cross join (select #prev_value := 0, #row_num := 0) vars
order by d.project_id, d.times
) d2
where prev_time <> ''
Results:
| project_id | id | prev_time | times |
|------------|----|-----------|-------|
| 20 | 14 | 12.22 | 13.22 |
| 40 | 13 | 12.24 | 13.22 |
| 40 | 32 | 13.30 | 22.24 |
| 40 | 36 | 23.22 | 23.3 |
| 70 | 34 | 22.22 | 23.22 |
Note: MySQL doe snot currently support LEAD() and LAG() functions when this answer was prepared. When MySQL does support these that approach would be simpler and probably more efficient.
select
d.*
from (
select
d1.*
, LEAD(times,1) OVER(partition by project_id order by times ASC) next_time
from (
select id, times, project_id from Table1
union all
select id, times, project_id from Table2
) d1
) d
where next_time is not null