Showing proper balance ammount - mysql

I have a query where I suppose to show debit, credit & balance. I have no balance column in table. I calculate the balance from debit & credit.
I tried to create a balance column where balance will be stored and display it from table. But if I update or delete any row the balance will not proper.
I found the below code on SO. But it works when there is one row for a one date, multiple columns for a date is not working properly. It display the balance with day by day, I want to display balance with row by row.
MySQL
SELECT
m.`id`,
m.`date`,
m.`credit`,
m.`debit`,
SUM(t.`credit`) - SUM(t.`debit`) AS `balance`
FROM `cash_book` m
JOIN (
SELECT
`id`,
`date`,
`credit`,
`debit`
FROM
`cash_book`
) t ON t.`date` <= m.`date`
WHERE `customer_id` = 1
GROUP BY
m.`id`
ORDER BY m.`date` ASC
It's return the result like this:
Date Debit Credit Balance
2016-11-27 0 2000 2000
2016-12-02 0 500000 585000 //same result for date 2016-12-02
2016-12-02 15000 0 585000 //same result for date 2016-12-02
2016-12-02 0 100000 585000 //same result for date 2016-12-02
2016-12-03 1200 0 583800
2016-12-04 3160 0 580540 //same result for date 2016-12-04
2016-12-04 100 0 580540 //same result for date 2016-12-04
2016-12-05 30 0 580510
2016-12-06 0 150 580660
But I want the result like this:
Date Debit Credit Balance
2016-11-27 0 2000 2000
2016-12-02 0 500000 502000
2016-12-02 15000 0 487000
2016-12-02 0 100000 587000
2016-12-03 1200 0 585800
2016-12-04 3160 0 582640
2016-12-04 100 0 582540
2016-12-05 30 0 582510
2016-12-06 0 150 582660

is it this what you looking for ?
SELECT
`id`,
`date`,
`credit`,
`debit`,
#balance := #balance + credit-debit AS balance
FROM `cash_book`
CROSS JOIN ( SELECT #balance := 0) as init
ORDER BY `date` ASC ;
sample
mysql> SELECT * FROM cash_book;
+------+------------+-------+--------+
| id | date | debit | credit |
+------+------------+-------+--------+
| 1 | 2016-11-27 | 0 | 2000 |
| 2 | 2016-12-04 | 3160 | 0 |
| 3 | 2016-12-02 | 15000 | 0 |
| 4 | 2016-12-03 | 1200 | 0 |
| 5 | 2016-12-05 | 30 | 0 |
| 6 | 2016-11-29 | 0 | 10000 |
| 7 | 2016-01-05 | 0 | 0 |
| 8 | 2016-12-01 | 2000 | 0 |
| 9 | 2016-11-29 | 10000 | 0 |
| 10 | 2016-12-02 | 2000 | 100000 |
| 11 | 2016-12-06 | 2000 | 150 |
| 12 | 2016-12-02 | 2000 | 500000 |
+------+------------+-------+--------+
12 rows in set (0,00 sec)
mysql> SELECT
-> `id`,
-> `date`,
-> `credit`,
-> `debit`,
-> #balance := #balance + credit-debit AS balance
-> FROM `cash_book`
-> CROSS JOIN ( SELECT #balance := 0) as init
-> ORDER BY `date` ASC ;
+------+------------+--------+-------+---------+
| id | date | credit | debit | balance |
+------+------------+--------+-------+---------+
| 7 | 2016-01-05 | 0 | 0 | 0 |
| 1 | 2016-11-27 | 2000 | 0 | 2000 |
| 6 | 2016-11-29 | 10000 | 0 | 12000 |
| 9 | 2016-11-29 | 0 | 10000 | 2000 |
| 8 | 2016-12-01 | 0 | 2000 | 0 |
| 3 | 2016-12-02 | 0 | 15000 | -15000 |
| 10 | 2016-12-02 | 100000 | 2000 | 83000 |
| 12 | 2016-12-02 | 500000 | 2000 | 581000 |
| 4 | 2016-12-03 | 0 | 1200 | 579800 |
| 2 | 2016-12-04 | 0 | 3160 | 576640 |
| 5 | 2016-12-05 | 0 | 30 | 576610 |
| 11 | 2016-12-06 | 150 | 2000 | 574760 |
+------+------------+--------+-------+---------+
12 rows in set (0,00 sec)
mysql>

You can use a subquery in select part like this
SELECT
m.`id`,
m.`date`,
m.`credit`,
m.`debit`,
(select sum(n.`credit`) - sum(n.`debit`)
from `cash_book` n
where n.`id` = m.`id`
and n.`date` <= m.`date`) balance
FROM `cash_book` m
WHERE `customer_id` = 1
ORDER BY m.`date` ASC

try this query
select s.Date,s.Debit,s.credit,ABS(#b := #b + s.debit - s.credit) as balance from (select #b:= 0.0) as dummy cross join cash_book as s order by ID;

In your Query you have used JOIN, That will used to join two or more tables. Here you are using only one table. So no need of JOIN inside the query.
You can use this following simple query,
SELECT
m.id,
m.date,
m.credit,
m.debit,
(SELECT SUM(credit)-SUM(debit)
FROM`cash_book` A
WHERE A.date<=m.Date)
FROM `cash_book` m WHERE m.customer_id = 1 ORDER BY m.Date ASC

Related

subtract multiple dates within one id

I'm trying to accomplish something in mySQL, which is difficult due to the lack of a "lag" function and because of all the examples I've read regarding date differences, since in all those examples there's always one ID to one date. In here, I am trying to do the date differences within an ID, and when the date difference is over 60, then returning an indicator of 1, else 0.
Not sure what the best way is to go about this. Would it be some combination of using row_number() with the date? The snag is doing this within multiple IDs, as a lot of things I read don't cover that. Any direction would be helpful.
Thanks!
ID | Service Date | Date Difference | Indicator
1 | 1/22/2016 | 0 | 1
1 | 3/26/2016 | 64 | 1
1 | 5/25/2016 | 60 | 0
1 | 9/15/2016 | 113 | 1
2 | 8/1/2016 | 0 | 1
3 | 1/26/2016 | 0 | 1
3 | 3/9/2016 | 43 | 0
3 | 4/30/2016 | 52 | 0
4 | 8/9/2016 | 0 | 1
5 | 11/19/2016 | 0 | 1
6 | 10/14/2016 | 0 | 1
7 | 1/31/2016 | 0 | 1
7 | 8/11/2016 | 193 | 1
You can use variables, but this is tricky. For this to work reliably, all the variables need to be assigned in a single expression:
select t.*, datediff(prev_date, date) as diff,
(case when datediff(prev_date, date) < 60 then 0 else 1 end) as indicator
from (select t.*,
(case when #id = id
then (case when (#prev := #d) = NULL then 'never' -- intentional
when (#d := date) = NULL then 'never' -- intentional
else #prev
end)
when (#d := date) = NULL then 'never' -- intentional
else NULL
end) as prev_date
from t cross join
(select #id := -1, #d := '') params
order by id, date
) t
create view id_and_date as
select id, service_date from your table;
create view id_and_date_and_prior as
select
a.id, a.service_date,
coalesce(
(select max(b.service_date) from id_and_date b
where b.id = a.id and b.service_date < a.service_date),
a.service_date)
as prior_date
from id_and_date a
select a.id, a.service_date, a.prior_date
date_diff(a.service_date, a.prior_date) as diff,
case when date_diff(a.service_date, a.prior_date) > 60
then 1 else 0 end
as indicator
from id_and_date_and_prior a
Posting to simplify and correct the function calls from the answer provided by #tpdi. Please accept/upvote their answer, as this was pretty much copied from it.
Changes:
date_diff to DATEDIFF
removed create view calls in favor of subquery of t
assigned variable to the diff value
indicator of 0 on initial value as 0 diff to 1
replaced when case in favor of IF
SELECT
c.id,
c.service_date,
#diff := DATEDIFF(c.service_date, c.prior_date) AS diff,
IF(#diff = 0 || #diff > 60, 1, 0) AS indicator
FROM (
SELECT
a.id,
a.service_date,
COALESCE(
(SELECT MAX(b.service_date)
FROM t AS b
WHERE b.id = a.id
AND b.service_date < a.service_date),
a.service_date
) AS prior_date
FROM t AS a
) AS c;
Will result in:
| id | service_date | diff | indicator |
| 1 | 2016-01-22 | 0 | 1 |
| 1 | 2016-03-26 | 64 | 1 |
| 1 | 2016-05-25 | 60 | 0 |
| 1 | 2016-09-15 | 113 | 1 |
| 2 | 2016-08-01 | 0 | 1 |
| 3 | 2016-01-26 | 0 | 1 |
| 3 | 2016-03-09 | 43 | 0 |
| 3 | 2016-04-30 | 52 | 0 |
| 4 | 2016-08-09 | 0 | 1 |
| 5 | 2016-11-19 | 0 | 1 |
| 6 | 2016-10-14 | 0 | 1 |
| 7 | 2016-01-31 | 0 | 1 |
| 7 | 2016-08-11 | 193 | 1 |

Using Mysql to select values from different tables with different names as credit and debit and calculate balance

I need to get values from different tables with different column names and select it as a common name that I could make a balance calculation.
Something like that:
Table 1 (credit)
+-----------+--------------+---------------+
| ID_company| date_table1 | credit_table1|
+-----------+--------------+---------------+
| 1 | 2017-08-19 | 50 |
| 1 | 2017-08-19 | 250 |
| 1 | 2017-08-20 | 0 |
+-----------+--------------+---------------+
Table 2 (credit)
+-----------+--------------+---------------+
| ID_company| date_table2 | credit_table2|
+-----------+--------------+---------------+
| 1 | 2017-08-19 | 150 |
| 1 | 2017-08-19 | 50 |
| 1 | 2017-08-19 | 0 |
+-----------+--------------+---------------+
Table 3 (debit)
+-----------+--------------+---------------+
| ID_company| date_table3 | debit_table3|
+-----------+--------------+---------------+
| 1 | 2017-08-19 | 10 |
| 1 | 2017-08-19 | 10 |
| 1 | 2017-08-20 | 0 |
+-----------+--------------+---------------+
Table 4 (debit)
+-----------+--------------+---------------+
| ID_company| date_table4 | debit_table4|
+-----------+--------------+---------------+
| 1 | 2017-08-19 | 10 |
| 1 | 2017-08-19 | 10 |
| 1 | 2017-08-20 | 0 |
+-----------+--------------+---------------+
Result
+-----------+--------------+---------------+--------------+---------+
| ID_company| date_grouped| total_debit | total_credit | balance |
+-----------+--------------+---------------+--------------+---------+
| 1 | 2017-08-19 | 20 | 200 | 180 |
| 1 | 2017-08-19 | 20 | 300 | 280 |
| 1 | 2017-08-20 | 0 | 0 | 0 |
+-----------+--------------+---------------+--------------+---------+
The relation between the tables is the ID_company, but the column names are different and I need to calculate the credit, debit and balance from all tables grouped by date.
I think this should work, even if there is no entry for a given date in up to three tables.
Balance is per day, not accumulative.
It will not produce your example result, but I think there's an error in your example. Do you really need two rows for ID 1 and the same date?
SELECT
ID_company,
date_grouped,
sum(credit_table1) + sum(credit_table2) total_credits,
sum(debit_tabel3) + sum(debit_table4) total_debit,
sum(debit_tabel3) + sum(debit_table4)
- (sum(credit_table1) + sum(credit_table2)) balance
FROM (
SELECT
ID_Company,
date_table1 date_grouped,
credit_table1,
0 credit_table2,
0 debit_table3,
0 debit_table4
FROM table1
UNION
SELECT
ID_Company,
date_table2 date_grouped,
0 credit_table1,
credit_table2,
0 debit_table3,
0 debit_table4
FROM table2
UNION
SELECT
ID_Company,
date_table3 date_grouped,
0 credit_table1,
0 credit_table2,
debit_table3,
0 debit_table4
FROM table3
UNION
SELECT
ID_Company,
date_table4 date_grouped,
0 credit_table1,
0 credit_table2,
0 debit_table3,
debit_table4
FROM table4
)
GROUP BY ID_company, date_grouped

Mysql Join Union Query By Date

I have 2 tables
and i want the result as this using join query. I don't have any Idea
Join Query By
TBL_SUCCESS_ORDER
------------------------
id | date | amount
-------------------------
1 | 2017-01-01 | 1000
2 | 2017-01-06 | 300
3 | 2017-01-29 | 50
4 | 2017-02-02 | 100
5 | 2017-02-16 | 400
6 | 2017-03-01 | 500
7 | 2017-04-03 | 1200
TBL_FAIL_ORDER
------------------------
id | date | amount
-------------------------
1 | 2017-01-03 | 400
2 | 2017-01-07 | 300
3 | 2017-01-24 | 50
4 | 2017-02-02 | 100
5 | 2017-04-07 | 200
RESULT
------------------------------------------------------------------
year | month | sum_of_succes_amount | sum_of_fail_amount | total
------------------------------------------------------------------
2017 | January | 1350 | 750 | 2100
2017 | Febuary | 500 | 100 | 600
2017 | March | 500 | 0 | 500
2017 | April | 1200 | 200 | 1400
I been stack for a whole week i did not get it . When i connect api json
TBL_PENDING_ORDER
------------------------
id | date | amount
-------------------------
1 | 2017-04-03 | 600
2 | 2017-05-07 | 600
RESULT
-----------------------------------------------------------------------------------------
year | month | sum_of_succes_amount | sum_of_fail_amount | sum_of_pending_amount |total
-----------------------------------------------------------------------------------------
2017 | January | 1350 | 750 | 0 | 2100
2017 | Febuary | 500 | 100 | 0 | 600
2017 | March | 500 | 0 | 0 | 500
2017 | April | 1200 | 200 | 600 | 2000
2017 | May | 0 | 0 | 600 | 600
What if I add The third table ? TBL_PENDING_ORDER
You can use the following solution using UNION ALL AND GROUP BY:
SELECT
YEAR(x.date),
MONTH(x.date),
SUM(CASE WHEN x.type = 'S' THEN amount ELSE 0 END) AS sum_of_succes_amount,
SUM(CASE WHEN x.type = 'F' THEN amount ELSE 0 END) AS sum_of_fail_amount,
SUM(amount) AS total
FROM (
SELECT id, date, amount, 'S' AS type FROM TBL_SUCCESS_ORDER
UNION ALL
SELECT id, date, amount, 'F' AS type FROM TBL_FAIL_ORDER
)x GROUP BY YEAR(x.date), MONTH(x.date)
You want to add the third table TBL_PENDING_ORDER?
SELECT
YEAR(x.date),
MONTH(x.date),
SUM(CASE WHEN x.type = 'S' THEN amount ELSE 0 END) AS sum_of_succes_amount,
SUM(CASE WHEN x.type = 'F' THEN amount ELSE 0 END) AS sum_of_fail_amount,
SUM(CASE WHEN x.type = 'P' THEN amount ELSE 0 END) AS sum_of_pending_amount,
SUM(amount) AS total
FROM (
SELECT id, date, amount, 'S' AS type FROM TBL_SUCCESS_ORDER
UNION ALL
SELECT id, date, amount, 'F' AS type FROM TBL_FAIL_ORDER
UNION ALL
SELECT id, date, amount, 'P' AS type FROM TBL_PENDING_ORDER
)x GROUP BY YEAR(x.date), MONTH(x.date)

Select multiple rows based on increments of a column value

I have a table (action_tbl) as follows:
ActionID | Frame | Player_ID
----------------------------
1234 | 15 | 1
1235 | 15 | 1
1236 | 30 | 1
1237 | 280 | 1
1238 | 10 | 2
1239 | 60 | 2
1240 | 320 | 2
I'd like to write a script in MySQL to count number of actions for each player during a 240 frame period (for frame between 0-240, Frame_Period is 0, 241-480, 1, etc).
So the output should be as follow:
Count_Actions | Frame_Period | Player_ID
----------------------------
3 | 0 | 1
1 | 1 | 1
2 | 0 | 2
1 | 1 | 2
Edited
Sql Fiddle Demo
SELECT frame_id as Frame_Period, `Player_ID`, count(*) as Count_Actions
FROM action_tbl a
JOIN (SELECT 0 as frame_id, 0 low_limit, 240 high_limit
UNION
SELECT 1 as frame_id, 241 low_limit, 480 high_limit
UNION
SELECT 2 as frame_id, 481 low_limit, 720 high_limit
UNION
SELECT 3 as frame_id, 721 low_limit, 960 high_limit
) as frame_range
ON a.`Frame` between frame_range.low_limit
and frame_range.high_limit
GROUP BY `Player_ID`, frame_id
ORDER BY `Player_ID`, frame_id
OUTPUT
| frame_id | Player_ID | Count_Actions |
|----------|-----------|---------------|
| 0 | 1 | 3 |
| 1 | 1 | 1 |
| 0 | 2 | 2 |
| 1 | 2 | 1 |
Second aproach
SELECT truncate((Frame - 1) / 240, 0) as Frame_Period,
`Player_ID`,
count(*) as Count_Actions
FROM action_tbl
GROUP BY `Player_ID`, Frame_Period
ORDER BY `Player_ID`, Frame_Period

add a new entry if doesn't exist in mysql table

Ok let me reframe my same question, to aim to the right output.
I have a table of below structure.
mysql> desc depot;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| recd | date | YES | | NULL | |
| id | int(11) | YES | | NULL | |
+-------+----------+------+-----+---------+-------+
Currently I have records in the below manner.
mysql> select * from depot;
+---------------------+------+
| recd | id |
+---------------------+------+
| 2012-07-09 | 33 |
| 2012-07-11 | 32 |
| 2012-07-15 | 32 |
+---------------------+------+
3 rows in set (0.00 sec)
I need the records to print the query in the below manner, keeping the missed entries of dates of a month (say July-01 to July-31) and having 0 to the value id corresponding missed dates.
select < a magical query >;
+------------+------+
| recd | id |
+------------+------+
2012-07-01 0
2012-07-02 0
2012-07-03 0
2012-07-04 0
2012-07-05 0
2012-07-06 0
2012-07-07 0
2012-07-08 0
2012-07-09 33
2012-07-10 0
2012-07-11 32
2012-07-12 0
2012-07-13 0
2012-07-14 0
2012-07-15 32
2012-07-16 0
2012-07-17 0
2012-07-18 0
2012-07-19 0
2012-07-20 0
2012-07-21 0
2012-07-22 0
2012-07-23 0
2012-07-24 0
2012-07-25 0
2012-07-26 0
2012-07-27 0
2012-07-28 0
2012-07-29 0
2012-07-30 0
2012-07-31 0
SELECT
generated_date,
COALESCE(yourTable.id, 0) AS id
FROM
(
SELECT
DATE_SUB(CURDATE(), INTERVAL number_days DAY) AS `generated_date` /*<-- Create dates from now back 999 days*/
FROM
(
SELECT (a + 10*b + 100*c) AS number_days FROM
(SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) aa
, (SELECT 0 AS b UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) bb
, (SELECT 0 AS c UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) cc
)sq /*<-- This generates numbers 0 to 999*/
) q
LEFT JOIN yourTable ON DATE(yourTable.datefield) = q.generated_date
WHERE q.generated_date BETWEEN (SELECT MIN(datefield) FROM yourTable) AND (SELECT MAX(datefield) FROM yourTable)
ORDER BY q.generated_date ASC
Found a workaround as it was clinging long time
BASE TABLE
CREATE TABLE `deopt` (
`recd` datetime DEFAULT NULL,
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB;
Seed records to the base table
insert into deopt values ('2012-07-09 23:08:54',22);
insert into deopt values ('2012-07-11 23:08:54',22);
insert into deopt values ('2012-07-11 23:08:54',2222);
insert into deopt values ('2012-07-12 23:08:54',22);
insert into deopt values ('2012-07-14 23:08:54',245);
Create a table for dates of a month
CREATE TABLE seq_dates
(
sdate DATETIME NOT NULL,
);
Create a Stored Procedure to create records for a called month
delimiter //
DROP PROCEDURE IF EXISTS sp_init_dates;
CREATE PROCEDURE sp_init_dates (IN p_fdate DATETIME, IN p_tdate DATETIME)
BEGIN
DECLARE v_thedate DATETIME;
TRUNCATE TABLE seq_dates;
SET v_thedate = p_fdate;
WHILE (v_thedate <= p_tdate) DO
INSERT INTO seq_dates (sdate)
VALUES (v_thedate);
SET v_thedate = DATE_ADD(v_thedate, INTERVAL 1 DAY);
END WHILE;
END;
delimiter ;
Call the procedure for July month with starting and ending values to be seeded to seq_dates table.
call sp_init_dates ('2012-07-01','2012-07-31');
RESULT QUERY - To fetch records of all dates in a month and its corresponding ids keeping 0 inplace of null for ids.
select date(seq_dates.sdate),coalesce (deopt.id,0) from seq_dates LEFT JOIN deopt ON date(deopt.recd)=date(seq_dates.sdate);
+-----------------------+-----------------------+
| date(seq_dates.sdate) | coalesce (deopt.id,0) |
+-----------------------+-----------------------+
| 2012-07-01 | 0 |
| 2012-07-02 | 0 |
| 2012-07-03 | 0 |
| 2012-07-04 | 0 |
| 2012-07-05 | 0 |
| 2012-07-06 | 0 |
| 2012-07-07 | 0 |
| 2012-07-08 | 0 |
| 2012-07-09 | 22 |
| 2012-07-09 | 22 |
| 2012-07-10 | 0 |
| 2012-07-11 | 22 |
| 2012-07-11 | 2222 |
| 2012-07-11 | 22 |
| 2012-07-11 | 2222 |
| 2012-07-12 | 22 |
| 2012-07-13 | 0 |
| 2012-07-14 | 245 |
| 2012-07-15 | 0 |
| 2012-07-16 | 0 |
| 2012-07-17 | 0 |
| 2012-07-18 | 0 |
| 2012-07-19 | 0 |
| 2012-07-20 | 0 |
| 2012-07-21 | 0 |
| 2012-07-22 | 0 |
| 2012-07-23 | 0 |
| 2012-07-24 | 0 |
| 2012-07-25 | 0 |
| 2012-07-26 | 0 |
| 2012-07-27 | 0 |
| 2012-07-28 | 0 |
| 2012-07-29 | 0 |
| 2012-07-30 | 0 |
| 2012-07-31 | 0 |
+-----------------------+-----------------------+
35 rows in set (0.00 sec)
As a two stage query:
SELECT #prev := null;
SELECT datefield, #prev, DATEDIFF(datefield, #prev) AS diff, #prev := datefield
FROM yourtable
HAVING diff > 1
ORDER BY datefield ASC;
that'll detect the dates that have a more-than-1-day difference from the previous row/date