I have a similar table:
+----+--------+--------+------------+-----------+
| id | amount | rif_id | date | is_closed |
+----+--------+--------+------------+-----------+
| 1 | 20 | NULL | 2017-11-12 | 1 |
| 2 | -5 | 1 | 2017-11-13 | NULL |
| 3 | -10 | 1 | 2017-11-24 | NULL |
| 4 | 7 | NULL | 2017-11-25 | 0 |
| 5 | -5 | 1 | 2017-11-26 | NULL |
| 6 | -5 | 4 | 2017-11-28 | NULL |
| 7 | 11.20 | NULL | 2017-11-30 | 0 |
+----+--------+--------+------------+-----------+
I need to get a list of more recent ID where SUM of amount is equal to zero, refering with rif_id.
In my example, I need to get this result:
+----+--------+--------+------------+-----------+
| id | amount | rif_id | date | is_closed |
+----+--------+--------+------------+-----------+
| 5 | -5 | 1 | 2017-11-26 | NULL |
+----+--------+--------+------------+-----------+
I need the ID 5 because that -5 amount, with sum of ID 1, 2 and 3, is exactly zero.
FYI, The column "is_closed" is updated with 1 when is inserted last transaction inside the table. In effect, when is inserted the ID 5, my script calculate and update the ID 1 with "is_closed" 1. Don't know if can be important for the SQL SELECT create.
I think you can do something like this:
get all records with the same ref_id and has id < the current record
Filter only the records with acumulated value equals 0. sum(t2.amount) = 0
Sort by the id and get the first one. Order by id desc Limit 1
Select
t1.id,
t1.amount,
t1.rif_id,
t1.date,
t1.is_closed
From
table t1
left join table t2 on t2.ref_id = t1.ref_id and t2.id < t1.id
Group by
t1.id,
t1.amount,
t1.rif_id,
t1.date,
t1.is_closed
Having
sum(t2.amount) = 0
Order by
id desc
Limit 1
Related
Let's say, in given num_table, there is a column, in which only numbers from 1 to 35 are stored.
Code for count nums in last 25rows is:
select num, count(*)
from (select C_1 as num from num_table order by id desc limit 25) n
group by num
order by num asc;
Result:
| num | count(*) |
|------|----------|
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 2 |
| 10 | 1 |
| 11 | 1 |
| 12 | 1 |
| 15 | 1 |
| 16 | 2 |
| 17 | 1 |
| 20 | 1 |
| 21 | 1 |
| 22 | 1 |
| 23 | 1 |
| 25 | 1 |
| 28 | 2 |
| 29 | 2 |
| 30 | 1 |
| 32 | 2 |
|------|----------|
How to get a result, where nums from 1 to 35 - which occured 0 times within last 25 rows - will be also displayed?
Example of desired result:
| num | count(*) |
|------|----------|
| 1 | 0 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 2 |
| 6 | 0 |
| 7 | 0 |
| 8 | 0 |
| 9 | 0 |
| 10 | 1 |
| ... | ... |
| 35 | 0 |
Maybe the quickest way is to make your existing query as sub-query and LEFT JOIN your num_table with it like :
SELECT A.C_1, IFNULL(cnt,0) total_count
FROM num_table A
LEFT JOIN
(SELECT num, COUNT(*) cnt
FROM (SELECT C_1 AS num FROM num_table ORDER BY id DESC LIMIT 25) n
GROUP BY num) B
ON A.C_1=B.num
GROUP BY A.C_1, cnt
ORDER BY A.C_1 ASC;
Here's a fiddle for reference:
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=3ced94d698fd8a55a8ad07a9d3b42f3d
And by the way, the current result you're showing is only 24 rows despite you did LIMIT 25 in the first sub-query. So in my example fiddle, the result is slightly different.
Here is another way to solve your problem.
In this solution, first, you need a table with numbers between 1 and 35, but only for the query, so then you can left join (because with a left join you can have also 0 counter values) it with your existent num_table.
You can do it like this:
WITH RECURSIVE numbers(id) AS (
SELECT 1 as id
UNION ALL
SELECT id+1 FROM numbers WHERE id < 35
)
SELECT numbers.id AS num, count(nt.id) AS total
FROM numbers
LEFT JOIN (SELECT C_1 FROM num_table ORDER BY id DESC LIMIT 25) nt ON (nt.C_1 = numbers.id)
GROUP BY numbers.id
I have this table:
| id | created_at | updated_at | visited_page | visited_date | user_id |
+----+----------------------------+----------------------------+-------------------+--------------+-----
| 1 | 2020-12-28 18:09:40.243560 | 2020-12-28 18:09:40.244170 | 1 | 2020-12-28 | 78557 |
| 2 | 2020-12-28 18:10:41.290824 | 2020-12-28 18:10:41.291217 | 1 | 2020-12-29 | 78557 |
| 3 | 2020-12-28 18:19:36.948853 | 2020-12-28 18:19:36.949289 | 3 | 2020-12-29 | 78557 |
+----+----------------------------+----------------------------+-------------------+--------------+-----
Here I want to fetch user_ids where the updated_at difference between two different pages visited by the same user is greater than 6 minutes on a particular date (in above tables case date = 2020-12-29).
Please explain how this query will look in SQL?
didn't test , but something like this should be the naswer :
SELECT DISTINCT t1.user_id
FROM table1 t1
JOIN table1 t2
ON t1.visiated_date = t2.visited_date
AND TIMESTAMPDIFF(MINUTE, t1.updated_at, t2.updated_at) > 6
AND t1.visited_page <> t2.visited_page
AND t1.date = 2020-12-29
I am working with a dataset with a similar format to the following:
Table: Account
*-----------*----------*-------------*
| id | amount | date |
*-----------*----------*-------------*
| 1 | 100 | 01/01/2016 |
| 2 | 100 | 01/02/2016 |
| 3 | 100 | 01/03/2016 |
| 4 | 200 | 01/04/2016 |
| 5 | 200 | 01/05/2016 |
| 6 | 200 | 01/06/2016 |
| 7 | 300 | 01/07/2016 |
| 8 | 300 | 01/08/2016 |
| 9 | 300 | 01/09/2016 |
| 10 | 400 | 01/10/2016 |
*-----------*----------*-------------*
I need a query to return that returns the most recent record for every distinct value in the table. So, the above table would return
*-----------*----------*-------------*
| id | amount | date |
*-----------*----------*-------------*
| 3 | 100 | 01/03/2016 |
| 6 | 200 | 01/06/2016 |
| 9 | 300 | 01/09/2016 |
| 10 | 400 | 01/10/2016 |
*-----------*----------*-------------*
I am still new to subqueries but I tried the following
SELECT a.id, a.amount, a.date FROM account a WHERE a.date IN (SELECT MAX(date) FROM account)
However this only return the latest date. How can I get the latest date for every distinct value in the amount column.
If you only need amount:
SELECT amount, MAX(date) from myTable group by amount
If you need more data:
SELECT * from myTable where (amount, date) IN (
SELECT amount, MAX(date) as date from table group by amount
)
Or maybe this will run faster:
SELECT * from myTable A WHERE NOT EXISTS (
SELECT 1
FROM myTable B
WHERE A.date < B.date
AND A.amount = B.amount
)
Let's say I have a table like this:
project_id | created_by | created
1 | 3 | 2015-04-01
2 | 3 | 2015-04-07
3 | 4 | 2015-05-01
4 | 4 | 2015-05-02
and I want to select these columns, then a count of how many projects were created by the created_by before each project, to look like this:
project_id | created_by | created | previous by created_by user
1 | 3 | 2015-04-01 | 0
2 | 3 | 2015-04-07 | 1
3 | 4 | 2015-05-01 | 0
4 | 4 | 2015-05-02 | 1
How do I select the count for that last column? I've tried count(case where [condition] then 1 else null end) but I keep only getting one row of results when I use that.
You can use a subquery which i already mentioned in the comments.
For Example the query could look like this:
SELECT t1.*,
(SELECT count(*)
FROM Table t2
WHERE UNIX_TIMESTAMP(t2.date) < UNIX_TIMESTAMP( t1.date)
AND t2.created_by = t1.created_by) before
FROM Table t1
It will return the columns of the the Table 'Table' and the result of the subquery as column 'before' which contains the count of before created rows.
Is this what you are after ?
select
project_id,
created_by,
created,
rn as `previous by created_by user`
from(
select
project_id,
created_by,
created,
#rn:=if(#prev_created_by = created_by,#rn+1,0) as rn,
#prev_created_by := created_by
from project,(select #rn:=0,#prev_created_by:=null)x
order by created_by,created
)x;
Here is a test case
mysql> select * from project ;
+------------+------------+------------+
| project_id | created_by | created |
+------------+------------+------------+
| 1 | 3 | 2015-04-01 |
| 2 | 3 | 2015-04-07 |
| 3 | 4 | 2015-05-01 |
| 4 | 4 | 2015-05-02 |
+------------+------------+------------+
4 rows in set (0.00 sec)
The above query will have
+------------+------------+------------+-----------------------------+
| project_id | created_by | created | previous by created_by user |
+------------+------------+------------+-----------------------------+
| 1 | 3 | 2015-04-01 | 0 |
| 2 | 3 | 2015-04-07 | 1 |
| 3 | 4 | 2015-05-01 | 0 |
| 4 | 4 | 2015-05-02 | 1 |
+------------+------------+------------+-----------------------------+
Select t1.project_id , t1.created_by, t1.created,count(t2.created)
from t1 , (select created_by,created from t1) as t2
Where t1.created_by=t2.created_by and t1.created>t2.created
group by t1.project_id ,t1.created_by, t1.created
In table I need to filter out nearest duplicated rows which have same status_id (but not completely all) when user_id is the same. GROUP BY or DISTINCT did not help in this situation. Here is an example:
---------------------------------------------------
| id | user_id | status_id | date |
---------------------------------------------------
| 1 | 10 | 1 | 2010-10-10 10:00:10|
| 2 | 10 | 1 | 2010-10-11 10:00:10|
| 3 | 10 | 1 | 2010-10-12 10:00:10|
| 4 | 10 | 2 | 2010-10-13 10:00:10|
| 5 | 10 | 4 | 2010-10-14 10:00:10|
| 6 | 10 | 4 | 2010-10-15 10:00:10|
| 7 | 10 | 2 | 2010-10-16 10:00:10|
| 8 | 10 | 2 | 2010-10-17 10:00:10|
| 9 | 10 | 1 | 2010-10-18 10:00:10|
| 10 | 10 | 1 | 2010-10-19 10:00:10|
Have to look like:
---------------------------------------------------
| id | user_id | status_id | date |
---------------------------------------------------
| 1 | 10 | 1 | 2010-10-10 10:00:10|
| 4 | 10 | 2 | 2010-10-13 10:00:10|
| 5 | 10 | 4 | 2010-10-14 10:00:10|
| 7 | 10 | 2 | 2010-10-16 10:00:10|
| 9 | 10 | 1 | 2010-10-18 10:00:10|
Oldest entries (by date) should remain in the table
You want to keep each row where the previous status is different, based on the id or date column.
If your ids are really sequential (as they are in the question), you can do this with a convenient join:
select t.*
from t left outer join
t tprev
on t.id = tprev.id+1
where tprev.id is null or tprev.status <> t.status;
If the ids are not sequential, you can get the previous one using a correlated subquery:
select t.*
from (select t.*,
(select t2.status
from t t2
where t2.user_id = t.user_id and
t2.id < t.id
order by t2.id desc
limit 1
) as prevstatus
from t
) t
where prevstatus is null or prevstatus <> t.status;