MYSQL select row before as previos data - mysql

This the example of the table name is merchant_point_log :
id created_date merchant_id point_value recent_point status
1 2022-01-02 1 5000 5000 earn
2 2022-01-02 2 3000 3000 earn
3 2022-01-02 1 3000 3000 redeem
i would like to show logging like with previous recent point in one row like :
id created_date merchant_id status previous_point point_value recent_point
1 2022-01-02 1 in 0 5000 5000
2 2022-01-02 1 out 5000 3000 2000
3 2022-01-02 2 in 0 3000 3000
how do i return previos_point column from before row of selected data ?
i already tried this query but still doesn't work as expected :
select
mpl.id
, mpl2.recent_point as previous_point
, mpl.point_value
, mpl.recent_point
from merchant_point_log mpl
left join merchant_point_log mpl2 on mpl.created_date = adddate(mpl2.created_date, 1)
order by mpl.id asc
;
the result is previous point dont return as expected it always repeat same value. I use mysql version 5.7

Here's an answer with left join for older versions where window functions are not an option.
select t.id
,t.created_date
,case t.status when 'earn' then 'in' else 'out' end as status
,coalesce(t2.recent_point, 0) as previous_point
,t.point_value
,t.recent_point
from t left join t t2 on t2.id = t.id-1
order by t.id
id
created_date
status
previous_point
point_value
recent_point
1
2022-01-02 00:00:00
in
0
2000
2000
2
2022-01-02 00:00:00
in
2000
5000
7000
3
2022-02-02 00:00:00
out
7000
3000
4000
Fiddle

We use lag to get previous_point and coalesce to put it as 0 in case previous_point is null.
select id
,created_date
,case status when 'earn' then 'in' else 'out' end as status
,coalesce(lag(recent_point) over (order by created_date), 0) as previous_point
,point_value
,recent_point
from t
id
created_date
status
previous_point
point_value
recent_point
1
2022-01-02 00:00:00
in
0
2000
2000
2
2022-01-02 00:00:00
in
2000
5000
7000
3
2022-02-02 00:00:00
out
7000
3000
4000
Fiddle

Related

Daily Sales from Total Sales

I have a database that looks like this:
ID
Sale_Date(YYYY-MM-DD)
Total_Volume
123
2022-01-01
0
123
2022-01-02
2
123
2022-01-03
5
456
2022-04-06
38
456
2022-04-07
40
456
2022-04-08
45
I want to get a daily sale column from Total Volume. which is just by subtracting the total volume on date x with total volume on date x-1 for each id.
ID
Sale_Date(YYYY-MM-DD)
Total_Volume
Daily_Sale
123
2022-01-01
0
0
123
2022-01-02
2
2
123
2022-01-03
5
3
456
2022-04-06
38
38
456
2022-04-07
40
2
456
2022-04-08
45
5
My initial attempt was using a rank function and self join but that didnt turn out correct.
with x as (
select
distinct t1.ID,
t1.Sale_Date,
t1.Total_volume,
rank() over (partition by ID order by Sale_Date) as ranker
from t t1 order by t1.Sale_Date)
select t2.ID, t2.ranker, t2.Sale_date, t1.Total_volume, t1.Total_volume - t2.Total_volume as Daily_sale
from x t1, x t2 where t1.ID = t2.ID and t2.ranker = t1.ranker-1 order by t1.ID;
You should use:
the LAG window function to retrieve last "Sale_Date" value
the COALESCE function to replace NULL with "Total Volume" for each first rows
Then subtract Total_Volume from the previous value of Total_Volume and coalesce if the value of the LAG is NULL.
SELECT *,
COALESCE(`Total_Volume`
-LAG(`Total_Volume`) OVER(PARTITION BY `ID`
ORDER BY `Sale_Date(YYYY-MM-DD)`), `Total_Volume`) AS `Daily_Sale`
FROM tab
Check the demo here.

How to LEFT JOIN more than 2 tables to get no records?

I want to get the date of this week and the total sum of total_price even there is no transaction on the specific date. The problem is when I change the value of tbl_barangay.city_id into 2, all the data of tbl_barangay.city_id = 1 is included. I want to get all records according to the value of tbl_barangay.city_id. How can I left join more than 2 tables so I can get the expected data?
Sample data
tbl_calendar tbl_city tbl_tran
date_id date city_id city_name tran_id tran_date city_id
1 2019-08-19 1 Sala 1 2019-08-19 1
2 2019-08-20 2 Marinig 2 2019-08-20 1
3 2019-08-21 3 Pulo 3 2019-08-23 2
4 2019-08-22
5 2019-08-23
6 2019-08-24
7 2019-08-25
tbl_tran_details
detail_id item total_price tran_id
1 Item1 20 1
2 Item2 20 1
2 Item3 30 2
2 Item1 30 3
Expected data if the tbl_city.city_id = 1
Date Total
2019-08-19 40
2019-08-20 30
2019-08-21 0
2019-08-22 0
2019-08-23 0
2019-08-24 0
and if the tbl_city.city_id = 2
Date Total
2019-08-19 0
2019-08-20 0
2019-08-21 0
2019-08-22 0
2019-08-23 30
2019-08-24 0
SELECT tbl_calendar.date Date,
SUM(IFNULL(tbl_tran_details.total_price,0)) Total FROM tbl_calendar
LEFT JOIN
tbl_tran ON tbl_calendar.date = tbl_tran.tran_date
LEFT JOIN
tbl_tran_details ON tbl_tran.tran_id = tbl_tran_details.tran_id
LEFT JOIN
tbl_city ON tbl_tran.city_id = tbl_city.city_id AND tbl_city.city_id = 2
WHERE
YEAR(tbl_calendar.date) = YEAR(NOW())
AND
WEEK(tbl_calendar.date) = WEEK(NOW())
GROUP BY
tbl_calendar.date
The problem is that you filter the cities in the wrong table because you want to get the sum of transactions for a certain city from the tbl_tran table, but you filter the cities in the tbl_city - which you do not even use in this query.
...
FROM (tbl_calendar
LEFT JOIN
tbl_tran ON tbl_calendar.date = tbl_tran.tran_date AND tbl_tran.city_id = 2)
LEFT JOIN
tbl_tran_details ON tbl_tran.tran_id = tbl_tran_details.tran_id
...

How to find users who are logged in but not logged out and is still logged in today in mysql?

The status 1 means Login and Status 0 means Logout. How do I find users who are logged in till now?
Here's the table
user_id time status
57 2015-10-21 09:00:00 1
57 2015-10-21 10:00:00 0
60 2015-10-21 12:30:00 1
55 2015-10-11 08:00:00 1
54 2015-10-21 09:00:00 1
54 2015-10-21 09:15:00 0
50 2015-10-21 08:15:00 1
49 2015-10-21 11:00:00 1
49 2015-10-21 11:00:00 0
Expected Result :
user_id status
55 1
60 1
55 1
50 1
You want users whose more recent status is 0.
Here is one method:
select t.*
from thetable t
where t.status = 1 and
not exists (select 1
from thetable t2
where t2.user_id = t.user_id and
t2.status = 0 and
t2.time > t.time
);
This can take advantage of two indexes: thetable(status, user_id) and thetable(user_id, status, time).
While the query presented so far is the most straightforward on I would like to show an alternative variant:
The number of entries of a user who is not logged in at the moment is alway even (pairs of 1 and 0). If a user is logged in, the number is odd.
Consequently:
select user_id, count(*), sum(status) from tee
group by user_id having count(*)/sum(status) <> 2

Increment Group Number based on row value SQL Server 2008

I have two tables that aren't really associated, but need to be combined. So I'm using union all on the two tables. The unioned tables are ordered by date, so rows from one table are dispersed among rows from the other table. What I need to do is get a running count of a column so I can group elements.
To explain further, table A holds dates of when a container is emptied, while table B holds daily entries for content of the container. I need to union the two tables so I have one table where I can get the sum of the information for a container before the container is emptied.
So I need something like this:
Table A:
Location_ID Empty Date
123 3/2/13
123 3/10/13
123 4/1/13
Table B:
PSI Entry Date Location_ID
120 2/28/13 123 (same for all)
130 3/1/13
100 3/8/13
110 3/9/13
200 3/18/13
180 3/20/13
So the unioned table after some magic would look like:
Table C...:
Location_ID Date PSI Emptied
123 2/28/13 120 0
123 3/1/13 130 0
123 3/2/13 null 1
123 3/8/13 100 0
123 3/9/13 110 0
123 3/10/13 null 1
123 3/18/13 200 0
123 3/20/13 180 0
123 4/1/13 null 1
What I need to do is have a grouping such that I can have a table like this
Table C_b
Location_ID Date PSI Emptied Group
123 2/28/13 120 0 1
123 3/1/13 130 0 1
123 3/2/13 null 1 1
123 3/8/13 100 0 2
123 3/9/13 110 0 2
123 3/10/13 null 1 2
123 3/18/13 200 0 3
123 3/20/13 180 0 3
123 4/1/13 null 1 3
How can I get that grouping in that way? I have to make it work in SQL Server 2008. I have tried using Count, and Rank, and Row_Number. But the problem with those is that it won't do a running count, it will just say the total count in each row.
Try this query:
DECLARE #MyTable TABLE(
EntryDate DATE NOT NULL,
Emptied BIT NOT NULL
);
INSERT INTO #MyTable (EntryDate,Emptied)
VALUES
('2013-01-01',0),
('2013-01-02',0),
('2013-01-03',1),
('2013-01-04',0),
('2013-01-05',0),
('2013-01-06',1),
('2013-01-07',0),
('2013-01-08',0),
('2013-01-09',1);
DECLARE #TableWithRowNum TABLE(
EntryDate DATE NOT NULL,
Emptied BIT NOT NULL,
RowNum INT PRIMARY KEY
);
INSERT INTO #TableWithRowNum (EntryDate,Emptied,RowNum)
SELECT crt.*,ROW_NUMBER() OVER(ORDER BY crt.EntryDate) AS RowNum
FROM #MyTable crt;
WITH RecCTE
AS(
SELECT
crt.EntryDate,
crt.Emptied,
crt.RowNum,
1 AS Grp
FROM #TableWithRowNum crt
WHERE crt.RowNum=1
UNION ALL
SELECT
crt.EntryDate,
crt.Emptied,
crt.RowNum,
CASE WHEN prev.Emptied=1 THEN prev.Grp+1 ELSE prev.Grp END
FROM #TableWithRowNum crt INNER JOIN RecCTE prev ON crt.RowNum=prev.RowNum+1
)
SELECT * FROM RecCTE
OPTION(MAXRECURSION 0); -- Default value for MAXRECURSION is 100
GO
Results:
EntryDate Emptied RowNum Grp
---------- ------- ------ ---
2013-01-01 0 1 1
2013-01-02 0 2 1
2013-01-03 1 3 1
2013-01-04 0 4 2
2013-01-05 0 5 2
2013-01-06 1 6 2
2013-01-07 0 7 3
2013-01-08 0 8 3
2013-01-09 1 9 3

MySQL Group By not producing expected result

This is my table structure:
rec_id product_id quantity quantity_in quantity_out balance stock_date status
1 2 342 NULL 17 325 2009-10-23 1
2 2 325 NULL 124 201 2009-10-23 1
3 1 156 NULL 45 111 2009-10-23 1
4 2 201 NULL 200 1 2009-10-23 1
5 2 1 NULL 1 0 2009-10-23 1
6 1 111 NULL 35 76 2009-10-23 1
All I want is the last transaction done for a given product: product_id, quantity, quantity_out and balance from this table.
Example, there are 2 transaction done for product 2 (ids 1 & 2):
final balance for product_id 2 is 0 -> stored in rec_id 5
final balance for product_id 1 is 76 -> stored in rec_id 6
Final result/output should be like this:
recid productid quantity quantityin quantityout balance stock_date status
5 2 1 NULL 1 0 2009-10-23 1
6 1 111 NULL 35 76 2009-10-23 1
You can find the latest record for each product like:
select max(rec_id) as MaxRec
from YourTable
group by product_id
Using a subquery, you can retrieve the latest rows for their product:
select *
from YourTable
where rec_id in (
select max(rec_id) as MaxRec
from YourTable
group by product_id
)
Here's a single query with no subqueries:
SELECT main.*
FROM YourTable main
LEFT JOIN YourTable newer
ON newer.product_id = main.product_id AND newer.rec_id > main.rec_id
WHERE newer.rec_id IS NULL;
You can tweak the field list however you want--make sure you select fields from main, not newer, which should be all null.