How to Get cumulative totals mysql - mysql

I have a table where I keep information about financial returns. The columns includes receipts, repairs, service_amount, tyres, fuel, salaries_allowances, others.
I would like to get the cumulative net return like:
Date Receipts repairs service amount Total costs net Return
2012-01-10 0.00 120,000.00 0.00 120,000.00 120,000.00
2012-01-12 60,000.00 0.00 0.00 60,000.00 60,000.00
I am currently using this query:
SELECT
a.consignment_date, a.receipts, a.service_amount, a.repairs, a.tyres,
a.salaries_allowances, a.clearing_fee, a.others,
a.service_amount + a.repairs + a.tyres + a.salaries_allowances + a.clearing_fee + a.others as total_costs,
(b.receipts -(a.service_amount + a.repairs + a.tyres + a.salaries_allowances + a.clearing_fee + a.others)) as netreturn
FROM
vw_local_freight a CROSS JOIN vw_local_freight b
WHERE
a.consignment_date >= b.consignment_date AND a.vehicle_no='123X'
GROUP BY a.consignment_date

I would look at a query like
SELECT
consignment_date.*,
consignment_date.credits - consignment_date.costs AS totalCosts,
(#runningTotal := #runningTotal + consignment_date.credits - consignment_date.costs) AS netReturn
FROM (
SELECT
consignment_date,
SUM(receipts) AS credits
SUM(service_amount + repairs + tyres + salaries_allowances + clearing_fee + others) AS costs
FROM vw_local_freight
WHERE vehicle_no = '123x'
GROUP BY consignment_date
) AS a, (SELECT #runningTotal := 0) AS b
The subquery tallies up your costs and credits, then the outer query performs your running total. If you need individual column sums within the inner join then they can be added in easily enough.

try this:
SET #runtot:=0;
SELECT
q1.d,
q1.c,
(#runtot := #runtot + q1.c) AS rt
FROM
(SELECT
DAYOFYEAR(date) AS d,
COUNT(*) AS c
FROM orders
WHERE hasPaid > 0
GROUP BY d
ORDER BY d) AS q1

Ok, I'm basing my answer on your query, rather than on your expected table result:
SELECT *, receipts - total_costs as NetReturn FROM (
SELECT a.consignment_date, sum(a.receipts) receipts, sum(a.service_amount),
sum(a.repairs), sum(a.tyres), sum(a.salaries_allowances),
sum(a.clearing_fee), sum(a.others), sum(a.service_amount + a.repairs
+ a.tyres + a.salaries_allowances + a.clearing_fee + a.others) as total_costs
FROM vw_local_freight a
WHERE a.vehicle_no = '123X'
GROUP BY a.consignment_date
) S

Related

How to get results from two sql query results

I"m using SET #runtot:=0 at the top of my SQL code and it gets 2 query results:
The first one is:
MySQL returned an empty result set (i.e. zero rows). (Query took
0.0002 seconds.)
The second is:
Showing rows 0 - 7 (8 total, Query took 0.0058 seconds.)
how can i get the results of the second query only?
here is my SQL code:
SET #runtot:=0;
SELECT
fname,
lname,
guests,
phone
FROM (
(SELECT *, 0 AS rt FROM guests_table WHERE status = 2)
UNION
(SELECT *, (#runtot := #runtot + rsvp.guests) AS rt
FROM
(SELECT *
FROM guests_table
WHERE status != 2
) AS rsvp
WHERE #runtot + rsvp.guests <= 4)
)rsvp
ORDER BY rsvp.id ASC
You can set the parameters in the query:
SELECT fname, lname, guests, phone
FROM ((SELECT *, 0 AS rt FROM guests_table WHERE status = 2)
UNION
(SELECT *, (#runtot := #runtot + rsvp.guests) AS rt
FROM (SELECT *
FROM guests_table
WHERE status != 2
) AS rsvp
WHERE #runtot + rsvp.guests <= 4)
) rsvp CROSS JOIN
(SELECT #runtot := 0) params
ORDER BY rsvp.id ASC;
Note that the use of variables in SELECT queries like this has been deprecated. In MySQL 8+, you should be using window functions.
In addition, the "running sum" is reading the rows in an arbitrary order. There is no guarantee that the result will be in the same order as the results.
If you want further help with the query, ask a new question. Provide sample data, desired results, and a clear explanation of the logic.

Mysql query get SUM() specific row?

Is it possible to get specific row in query using like SUM?
Example:
id tickets
1 10 1-10 10=10
2 35 11-45 10+35=45
3 45 46-90 10+35+45=90
4 110 91-200 10+35+45+110=200
Total: 200 tickets(In SUM), I need to get row ID who have ticket with number like 23(Output would be ID: 2, because ID: 2 contains 11-45tickets in SUM)
You can do it by defining a local variable into your select query (in form clause), e.g.:
select id, #total := #total + tickets as seats
from test, (select #total := 0) t
Here is the SQL Fiddle.
You seem to want the row where "23" fits in. I think this does the trick:
select t.*
from (select t.*, (#total := #total + tickets) as running_total
from t cross join
(select #total := 0) params
order by id
) t
where 23 > running_total - tickets and 23 <= running_total;
SELECT
d.id
,d.tickets
,CONCAT(
TRIM(CAST(d.RunningTotal - d.tickets + 1 AS CHAR(10)))
,'-'
,TRIM(CAST(d.RunningTotal AS CHAR(10)))
) as TicketRange
,d.RunningTotal
FROM
(
SELECT
id
,tickets
,#total := #total + tickets as RunningTotal
FROM
test
CROSS JOIN (select #total := 0) var
ORDER BY
id
) d
This is similar to Darshan's answer but there are a few key differences:
You shouldn't use implicit join syntax, explicit join has more functionality in the long run and has been a standard for more than 20 years
ORDER BY will make a huge difference on your running total when calculated with a variable! if you change the order it will calculate differently so you need to consider how you want to do the running total, by date? by id? by??? and make sure you put it in the query.
finally I actually calculated the range as well.
And here is how you can do it without using variables:
SELECT
d.id
,d.tickets
,CONCAT(
TRIM(d.LowRange)
,'-'
,TRIM(
CAST(RunningTotal AS CHAR(10))
)
) as TicketRange
,d.RunningTotal
FROM
(
SELECT
t.id
,t.tickets
,CAST(COALESCE(SUM(t2.tickets),0) + 1 AS CHAR(10)) as LowRange
,t.tickets + COALESCE(SUM(t2.tickets),0) as RunningTotal
FROM
test t
LEFT JOIN test t2
ON t.id > t2. id
GROUP BY
t.id
,t.tickets
) d

My SQL - Refer data from another table rows

I have no idea whether it is possible or not.
I have two tables:
Columns in hospitals Table
hospitalID
Name
AverageRating
Columns in ratings Table
ID
rating1
rating2
rating3
rating4
rating5
rating6
hospitalID
rating1 to rating6 is types of ratings. Now By calculation I am able to get average rating of particular hospital in ratings table from following SELECT Query
SELECT IFNULL((SUM(charges) + SUM(behaviour) + SUM(admission) + SUM(properInformation)
+ SUM(hygine) + SUM(treatment))/(count(hospitalID) * 6), 0
) AverageRating,COUNT(ID) RatingCount
FROM ratings
WHERE hospitalID = '111111'
Above query works for me perfectly but this averageRating I also want to calculate in my hospitals table because I want to ranks hospitals.
Is there any functions in mySQL through which I can calculate average rating to hospitals table by referring ratings table.
Rating Table
Query Output Table
Based on the given table structure, you can try this.
EDIT
SELECT avgratings.*, #curRow := #curRow + 1 AS hospitalRank
FROM (
SELECT (SUM(r.`rating1`)+SUM(r.`rating2`)+SUM(r.`rating3`)+SUM(r.`rating4`)+SUM(r.`rating5`)+SUM(r.`rating6`))/(COUNT(r.`hospitalID`)*6) AS AverageRating, h.hospitalID
FROM hospitals h INNER JOIN ratings r
ON h.`hospitalID`=r.`hospitalID`
WHERE 1 GROUP BY r.`hospitalID`
) avgratings JOIN (SELECT #curRow := 0) rank
ORDER BY avgratings.AverageRating DESC
2nd Query to get rank of a particular hospital.
SELECT tablea.*
FROM (
SELECT avgratings.*, #curRow := #curRow + 1 AS hospitalRank
FROM (
SELECT (SUM(r.`rating1`)+SUM(r.`rating2`)+SUM(r.`rating3`)+SUM(r.`rating4`)+SUM(r.`rating5`)+SUM(r.`rating6`))/(COUNT(r.`hospitalID`)*6) AS AverageRating, h.hospitalID
FROM hospitals h INNER JOIN ratings r
ON h.`hospitalID`=r.`hospitalID`
WHERE 1 GROUP BY r.`hospitalID`
) avgratings JOIN (SELECT #curRow := 0) rank
) tablea
WHERE tablea.hospitalID=1 ORDER BY tablea.AverageRating DESC
Replace 1 in WHERE block with hospitalID.
I am not sure I understand your question...
You get the avarage of a single record with:
charges + behaviour + admission + properInformation + hygine + treatment / 6
You get the total avarage hence with:
avg(charges + behaviour + admission + properInformation + hygine + treatment / 6)
I order to get it per hospital, you'd group by hospital_id:
select
hospitalid,
avg(charges + behaviour + admission + properinformation + hygine + treatment / 6) as avr,
count(*) as rating_count
from ratings
group by hospitalid
order by 2 desc;
You can select the hospital data (e.g. the hospital name) along by joining the hospital table. E.g.
select
h.hospitalid,
h.name,
avg(r.charges + r.behaviour + r.admission +
r.properinformation + r.hygine + r.treatment / 6) as average_rating,
count(*) as rating_count
from hospitals h
left join ratings r on r.hospitalid = h.hospitalid
group by h.hospitalid
order by average_rating desc;

Mysql recursive substracting and multiplying values

Couldn't really explain my problem with words, but with an example I can show it clearly:
I have a table like this:
id num val
0 3 10
1 5 12
2 7 12
3 11 15
And I want to go through all the rows, and calculate the increase of the "num", and multiply that difference with the "val" value. And when I calculated all of these, I want to add these results together.
This is the mathematical equation, that I want to run on the table:
Result = (3-0)*10 + (5-3)*12 + (7-5)*12 + (11-7)*15
138 = Result
Thank you.
You can do with mysql variables, but you will still get one record for each entry.
select
#lastTotal := #lastTotal + ( (yt.num - #lastNum) * yt.val ) thisLineTotal,
#lastNum := yt.num as saveForNextRow,
yt.id
from
yourTable yt,
( select #lastTotal := 0,
#lastNum := 0 ) sqlvars
order by
id
This SHOULD give you what you want to confirm the calculations to each record basis.
Now, to get the one record and one column result, you can wrap it such as
select
pq.thisLineTotal
from
(above entire query ) as pq
order by
pq.id DESC
limit 1
Assuming the IDs are consecutive as your sample data suggests, just join the table to itself:
select sum((t1.num-ifnull(t2.num,0))*t1.val) YourValue
from YourTable t1
left join YourTable t2
on t2.id = t1.id - 1;
http://www.sqlfiddle.com/#!2/40b9f/12
This will give you the total. Make sure to order in the order you wish - I have ordered by id
SET #runtot:=0;
SET #prevval:=0;
select max(rt) as total FROM (
SELECT
q.val,
q.num,
(#runtot := #runtot + (q.num- #prevval) * q.val) AS rt,
(#prevval := q.num) AS pv
FROM thetable q
ORDER by ID) tot
If you want to see the details of the calculation, leave out the outer select as so:
SET #runtot:=0;
SET #prevval:=0;
SELECT
q.val,
q.num,
(#runtot := #runtot + (q.num- #prevval) * q.val) AS rt,
(#prevval := q.num) AS pv
FROM thetable q
ORDER by ID
If it is possible to have negative numbers for your column values, using max(rt) won't work for the total. You should then use:
SET #runtot:=0;
SET #prevval:=0;
select #runtot as total FROM (
SELECT
q.val,
q.num,
(#runtot := #runtot + (q.num- #prevval) * q.val) AS rt,
(#prevval := q.num) AS pv
FROM thetable q
ORDER by ID) tot LIMIT 1

Can I do a mysql command to filter and delete duplicated entry

I have table as linkage with below values
++++++++++++++++++++++++++
+ company_id + industry +
++++++++++++++++++++++++++
+ 1 + a +
+ 1 + b +
+ 2 + a +
+ 2 + c +
+ 3 + a +
+ 4 + c +
+ 5 + a +
++++++++++++++++++++++++++
Is there a way that i can group my industry to get the top count sort by desc order example.
a = count 4
c = count 2
b = count 1
then delete duplicated industry leaving only the industry that has the higher count for each company_id.
Edit 1
This edit is based on OP comment I wish to only have the industry with the highest count, and deleting the rest of the entry for the same company_id. say for company_id 1, we will delete the second row, for company_id 2 we will delete the forth row.
Below is what I have.
++++++++++++++++++++++++++
+ company_id + industry +
++++++++++++++++++++++++++
+ 1 + a +
+ 1 + b +
+ 1 + c +
+ 2 + a +
+ 2 + c +
+ 3 + a +
+ 4 + c +
+ 5 + a +
++++++++++++++++++++++++++
as we see in column industry, a has max count, I would like to keep this entry per duplicated company_id and remove rest all enteries.
Consider company_id=1. I would need to remove second and third row.
Consider company_id=2. I would need to remove fifth row.
For id=3,4,5 nothing will happen as those are not duplicated.
So final data that should be there in my table is
++++++++++++++++++++++++++
+ company_id + industry +
++++++++++++++++++++++++++
+ 1 + a +
+ 2 + a +
+ 3 + a +
+ 4 + c +
+ 5 + a +
++++++++++++++++++++++++++
select t6.company_id,t6.industry from
(select t5.company_id,t5.industry,
row_number() over (partition by t5.company_id order by t5.company_id) rn
from
(select t3.company_id,t4.industry from
(select t2.company_id,max(t2.count) count from(
select m.company_id,m.industry,t1.count from linkage m
join
(select n.industry,count(n.industry) count from linkage n
group by n.industry
order by count desc)t1
on m.industry = t1.industry
order by m.company_id)t2
group by t2.company_id
order by t2.company_id)t3
join
(
select m.company_id,m.industry,t1.count from linkage m
join
(select n.industry,count(n.industry) count from linkage n
group by n.industry
order by count desc)t1
on m.industry = t1.industry
order by m.company_id)t4
on t3.company_id = t4.company_id
and t3.count = t4.count)t5
)t6
where t6.rn = '1'
How about this?
SELECT industry, count(industry) as "total"
FROM linkage
GROUP BY industry
ORDER BY total DESC
Demo at sqlfiddle
Edit 1
Can you take at look at below question.
how can I delete duplicate records from my database
I think that is what you are looking for.
select n.industry,count(n.industry) count from linkage n
group by n.industry
order by count desc
select t3.company_id,t4.industry from
(select t2.company_id,max(t2.count) count from(
select m.company_id,m.industry,t1.count from linkage m
join
(select n.industry,count(n.industry) count from linkage n
group by n.industry
order by count desc)t1
on m.industry = t1.industry
order by m.company_id)t2
group by t2.company_id
order by t2.company_id)t3
join
(
select m.company_id,m.industry,t1.count from linkage m
join
(select n.industry,count(n.industry) count from linkage n
group by n.industry
order by count desc)t1
on m.industry = t1.industry
order by m.company_id)t4
on t3.company_id = t4.company_id
and t3.count = t4.count
Demo at sqlfiddle