How to create RUNNING TOTAL in this mysql query - mysql

select saleid, orderno, orderdate,
sum(purchaseprice+purchaseshipping+paypalfee+storefee) as totalcost,
customerpaid as totalrevenue,
(customerpaid - sum(purchaseprice+purchaseshipping+paypalfee+storefee)) as profit,
ROUND((((customerpaid - sum(purchaseprice+purchaseshipping+paypalfee+storefee)) / customerpaid) * 100.00),2) as profitmargin
from tblsales
group by orderno having " . $having . "
order by $sort $order limit $offset,$rows
This query works fine. Is there a way to add running total profit field to this query that performs a running sum of profit already calculated in the query?

Just put it in a subquery and use variables:
select t.*,
(#cumesum := #cumesum + profit) as runningprofit
from (select saleid, orderno, orderdate,
sum(purchaseprice+purchaseshipping+paypalfee+storefee) as totalcost,
customerpaid as totalrevenue,
(customerpaid - sum(purchaseprice+purchaseshipping+paypalfee+storefee)) as profit,
ROUND((((customerpaid - sum(purchaseprice+purchaseshipping+paypalfee+storefee)) / customerpaid) * 100.00),2) as profitmargin
from tblsales
group by orderno
having " . $having . "
) t cross join
(select #cumesum := 0) vars
order by $sort $order
limit $offset, $rows;

Related

How to subtract two calculated fields from the same table in MySQL?

SELECT *,
SUM(price+shipping+paypalfee+storefee) AS totalcost,
customerpaid AS totalrevenue,
(totalcost - totalrevenue) AS profit
FROM tblsales
GROUP BY orderno
HAVING " . $having . "
ORDER BY $sort $order
LIMIT $offset,$rows
If I omit (totalcost - totalrevenue) as profit the query works fine. How could I calculate PROFIT in the same query using totalcost and totalrevenue?
The answer to your question is that you have to repeat the expressions:
select *, sum(price+shipping+paypalfee+storefee) as totalcost
customerpaid as totalrevenue,
(sum(price+shipping+paypalfee+storefee) - customerpaid) as profit
from tblsales
group by orderno
having " . $having . "
order by $sort $order
limit $offset, $rows;
You are not allowed to use a column alias in the same select where it is defined.
And, your query looks weird. Any query that has select * and group by is suspect. You have many columns (presumably) whose value will come from an indeterminate row for each group. You should explicitly list the columns in general, but you should especially do so for a group by.
You can do like this
SELECT * , (totalcost - totalrevenue) AS profit FROM(
SELECT *,
SUM(price+shipping+paypalfee+storefee) AS totalcost,
customerpaid AS totalrevenue,
FROM tblsales
GROUP BY orderno
HAVING " . $having . "
ORDER BY $sort $order )
LIMIT $offset,$rows

Adding up Alias with other MySQL column value

I have one problem with this query; I can't seem to get ((total + rec_host) / 2) AS total2 to work. How would I go about this procedure without doing:
((((rank_ur + rank_scs + rank_tsk + rank_csb + rank_vfm + rank_orr) / 6) + rec_host ) / 2)
Here's my Query:
SELECT host_name,
SUM(rank_ur) AS cnt1,
SUM(rank_scs) AS cnt2,
SUM(rank_tsk) AS cnt3,
SUM(rank_csb) AS cnt4,
SUM(rank_vfm) AS cnt5,
SUM(rank_orr) AS cnt6,
SUM(IF(rec_host = 1,1,0)) AS rh1,
SUM(IF(rec_host = 0,1,0)) AS rh2,
((rank_ur + rank_scs + rank_tsk + rank_csb + rank_vfm + rank_orr) / 6) AS total,
((total + rec_host) / 2) AS total2
FROM lhr_reviews
GROUP BY host_name
ORDER BY total
DESC LIMIT 0,10
Use a subquery like so:
SELECT
host_name,
cnt1,
cnt2,
cnt3,
cnt4,
cnt5,
cnt6,
rh1,
rh2,
total,
((total + rec_host) / 2) AS total2
FROM
(
SELECT host_name,
rec_host,
SUM(rank_ur) AS cnt1,
SUM(rank_scs) AS cnt2,
SUM(rank_tsk) AS cnt3,
SUM(rank_csb) AS cnt4,
SUM(rank_vfm) AS cnt5,
SUM(rank_orr) AS cnt6,
SUM(IF(rec_host = 1,1,0)) AS rh1,
SUM(IF(rec_host = 0,1,0)) AS rh2,
((rank_ur + rank_scs + rank_tsk +
rank_csb + rank_vfm + rank_orr
) / 6) AS total
FROM lhr_reviews
GROUP BY host_name, rec_host
) t
ORDER BY total
DESC LIMIT 0,10;
What you could do is this:
select x.*, ((x.total + rec_host) / 2) AS total2
from (
SELECT host_name, rec_host,
SUM(rank_ur) AS cnt1,
SUM(rank_scs) AS cnt2,
SUM(rank_tsk) AS cnt3,
SUM(rank_csb) AS cnt4,
SUM(rank_vfm) AS cnt5,
SUM(rank_orr) AS cnt6,
SUM(IF(rec_host = 1,1,0)) AS rh1,
SUM(IF(rec_host = 0,1,0)) AS rh2,
((rank_ur + rank_scs + rank_tsk + rank_csb + rank_vfm + rank_orr) / 6) AS total
FROM lhr_reviews
GROUP BY host_name
ORDER BY total
DESC LIMIT 0,10
) as x
;
You cannot use the column as an alias when the alias and other column are in the same level of SELECT. So you can use a derived query which lets you basically rename your columns and/or name any computed columns.Check on Rubens Farias and Rob Van Dam answer here
PS: will search for a better article to update the answer :)

Sum two rows (one previous row and one is current row in same table) in SQL

I have this table:
Date_on deposited withdrawal in_bank
2012-09-1 3000 2000 50000
2012-09-2/t 4000/t 0 54000
2013-09-3/t 3000 2000 55000
Now I want to execute a query to add the deposited amounts and subtract the withdrawals from the previous days entry in_bank. How can I do that? Can any one help me on that? This is my query:
select date_on, in_bank,((in_bank+deposited)-withdrawal)
from tablename where date_on > '2012-09-01' order by date_on
SELECT today.withdrawal, today.deposited, today.date_on,
(IFNULL(today.deposited, 0) - IFNULL(today.withdrawal, 0)) + IFNULL((SELECT in_bank FROM tablename AS yesterday WHERE yesterday.date_on = DATE_SUB(today.date_on, INTERVAL 1 DAY)), 0)
FROM tablename AS today
WHERE date_on BETWEEN '2012-09-01' AND '2012-09-02'
ORDER BY date_on ASC
The query will assume the balance was zero if no previous days date can be found.
Added a fiddle
http://sqlfiddle.com/#!2/d8261/14
Try this:
SELECT
t1.date_on,
t1.in_bank,
(
SELECT in_bank
FROM
(
SELECT *, (#rownum2 := #rownum2 +1) rank
FROM Table1,(SELECT #rownum2 :=0 ) t
ORDER BY date_on
) t2 WHERE t1.rank - t2.rank = 1
) - t1.withdrawal - deposited "total"
FROM
(
SELECT *, (#rownum := #rownum +1) rank
FROM Table1,(SELECT #rownum :=0 ) t
ORDER BY date_on
) t1;
SQL Fiddle Demo
SELECT
date_on,
in_bank,
(( ISNULL(in_bank, 0) + ISNULL(in_deposited,0)) - ISNULL(withdrawal,0))
FROM tablename
WHERE date_on > '2012-09-01'
ORDER BY date_on
I am not very familiar with mysql but this might help
select account.*,D.expectable from account left join
(
select deposited - withdrawal + in_bank as expectable,DATE_ADD(Date_on,INTERVAL 1 DAY) as nDate from account
)
D on account.Date_on = D.nDate

Cumulative count over time

I have a table orders like this:
customer_id order_date
10 2012-01-01
11 2012-01-02
10 2012-01-02
12 2012-01-03
11 2012-01-04
12 2012-02-01
11 2012-02-04
13 2012-02-05
14 2012-02-06
How can I get a cumulative average over time (per month) like this:
order date count orders count customers (customer_id)
2012-01 1 1 (12)
2012-01 2 2 (10,11)
2012-02 1 2 (13,14)
2012-02 2 2 (10,12
2012-02 3 2 (11)
showing how the number of customers vs. number of orders per customer develops over time.
The following query gives me the wanted information - but not over time. How can I iterate the query over time?
SELECT number_of_orders, count(*) as amount FROM (
SELECT o.customer_id, count(*) as number_of_orders
FROM orders o
GROUP BY o.customer_id) as t1
GROUP BY number_of_orders
Update:
have now build the following PHP code to generate what I need, wonder if that could be done using cumulative counts like on http://www.freeopenbook.com/mysqlcookbook/mysqlckbk-chp-12-sect-14.html
$year = 2011;
for ($cnt_months = 1; $cnt_months <= 12; $cnt_months++) {
$cnt_months_str = ($cnt_months < 10) ? '0'.$cnt_months : $cnt_months;
$raw_query = "SELECT number_of_orders, count(*) as amount
FROM (
SELECT
o.customer_id,
count(*) as number_of_orders
FROM orders o
where Date_Format( o.order_date, '%Y%m' ) >= " . $year . "01 and Date_Format( o.order_date, '%Y%m' ) <= " . $year . $cnt_months_str . "
GROUP BY o.customer_id) as t1
GROUP BY number_of_orders";
$query = db_query($raw_query);
while ($row = db_fetch_array($query)) {
$data[$cnt_months_str][$row['number_of_orders']] = array($row['number_of_orders'], (int)$row['amount']);
}
}
A good starting point is
SELECT
order_date,
COUNT(*) AS distinctOrders,
COUNT(DISTINCT customer_id) AS distinctCustomers,
GROUP_CONCAT(DISTINCT customer_id ASC) AS customerIDs
FROM orders
GROUP BY order_date ASC
This will give you the order_date, the number of orders on that date, the number of customers on that date, and the list of customer ids on that date.
Just looking at a way to tally up on a month by month basis. So taking this forward I've used a subquery to tally up as it goes
SELECT
ordersPerDate.*,
IF(
MONTH(ordersPerDate.order_date)=#thisMonth,
#runningTotal := #runningTotal+ordersPerDate.distinctOrders,
#runningTotal := 0
) AS ordersInThisMonth,
#thisMonth := MONTH(ordersPerDate.order_date)
FROM
(
SELECT
#thisMonth := 0,
#runningTotal := 0
) AS variableInit,
(
SELECT
order_date,
COUNT(*) AS distinctOrders,
COUNT(DISTINCT customer_id) AS distinctCustomers,
GROUP_CONCAT(DISTINCT customer_id ASC) AS customerIDs
FROM orders
GROUP BY order_date ASC
) AS ordersPerDate
And finally to clean it up, wrapped it in yet another subquery just to return the rows desired rather than the internal variables
Grouping on individual days
SELECT
collatedData.order_date,
collatedData.ordersInThisMonth AS count_orders,
collatedData.distinctCustomers AS count_customers,
collatedData.customerIDs AS customer_ids
FROM (
SELECT
ordersPerDate.*,
IF(
MONTH(ordersPerDate.order_date)=#thisMonth,
#runningTotal := #runningTotal+ordersPerDate.distinctOrders,
#runningTotal := 0
) AS ordersInThisMonth,
#thisMonth := MONTH(ordersPerDate.order_date)
FROM
(
SELECT
#thisMonth := 0,
#runningTotal := 0
) AS variableInit,
(
SELECT
order_date,
COUNT(*) AS distinctOrders,
COUNT(DISTINCT customer_id) AS distinctCustomers,
GROUP_CONCAT(DISTINCT customer_id) AS customerIDs
FROM orders
GROUP BY order_date ASC
) AS ordersPerDate
) AS collatedData
And now finally, following additional information from the OP, the end product
Grouping on calendar months
// Top level will sanitise the output
SELECT
collatedData.orderYear,
collatedData.orderMonth,
collatedData.distinctOrders,
collatedData.ordersInThisMonth AS count_orders,
collatedData.distinctCustomers AS count_customers,
collatedData.customerIDs AS customer_ids
FROM (
// This level up will iterate through calculating running totals
SELECT
ordersPerDate.*,
IF(
(ordersPerDate.orderYear,ordersPerDate.orderMonth) = (#thisYear,#thisMonth),
#runningTotal := #runningTotal+ordersPerDate.distinctOrders*ordersPerDate.distinctCustomers,
#runningTotal := 0
) AS ordersInThisMonth,
#thisMonth := ordersPerDate.orderMonth,
#thisYear := ordersPerDate.orderYear
FROM
(
SELECT
#thisMonth := 0,
#thisYear := 0,
#runningTotal := 0
) AS variableInit,
(
// Next level up will collate this to get per year, month, and per number of orders
SELECT
ordersPerDatePerUser.orderYear,
ordersPerDatePerUser.orderMonth,
ordersPerDatePerUser.distinctOrders,
COUNT(DISTINCT ordersPerDatePerUser.customer_id) AS distinctCustomers,
GROUP_CONCAT(ordersPerDatePerUser.customer_id) AS customerIDs
FROM (
// Inner query will get the number of orders for each year, month, and customer
SELECT
YEAR(order_date) AS orderYear,
MONTH(order_date) AS orderMonth,
customer_id,
COUNT(*) AS distinctOrders
FROM orders
GROUP BY orderYear ASC, orderMonth ASC, customer_id ASC
) AS ordersPerDatePerUser
GROUP BY
ordersPerDatePerUser.orderYear ASC,
ordersPerDatePerUser.orderMonth ASC,
ordersPerDatePerUser.distinctOrders DESC
) AS ordersPerDate
) AS collatedData
SELECT
substr(order_date,1,7) AS order_period,
count(*) AS number_of_orders,
count(DISTINCT orders.customer_id) AS number_of_customers,
GROUP_CONCAT(DISTINCT orders.customer_id) AS customers
FROM orders
GROUP BY substr(order_date,1,7)

Order of "id" changed in subquery?

I have this query
SELECT bul.id
FROM bul
WHERE id IN (SELECT hotid AS parentid
FROM likehot
WHERE hotid IN (SELECT id
FROM bul
WHERE DATE >= '1315976410')
GROUP BY hotpid
ORDER BY COUNT( hotid ) DESC )
when I runt this inner query
SELECT id
FROM bul
WHERE DATE >= '1315976410')
GROUP BY hotpid
ORDER BY COUNT( hotid ) DESC
I get
parentid
3655
3656
3622
3644
and when I run whole query I get
parentid
3656
3655
3622
3644
I really don't understand why the order of the ids change?
SOLUTION :-
<?php
$query_hotpress_like = "SELECT hotid AS parentid FROM likehot WHERE hotid IN (SELECT id FROM bul WHERE DATE >= '" . (time() - (24 * 60 * 60)) . "') GROUP BY hotid ORDER BY COUNT( hotid ) DESC";
$exe_hotpress_like = execute_query($query_hotpress_like, true, "select");
$temp_like1 = array();
foreach ($exe_hotpress_like as $kk => $exe_like) {
$temp_like1[] = "'" . $exe_like['parentid'] . "'";
}
$temp_like = str_replace(",''", "", implode(',', $temp_like1));
$query_hotpress = "SELECT bul.id,photo_album_id,eventcmmnt_id,link_url,youtubeLink,link_image,id, mem_id, subj, body, bul.date,parentid, from_id, visible_to,image_link,post_via FROM bul WHERE id IN ($temp_like) ORDER BY FIELD(id,$temp_like ) LIMIT 5";
?>
execute_query() is the inbuilt function to get the result of query.
That happens because for IN operator order doesn't matter.
If you need to sort outer query - sort outer query.
Since you didn't specify an order for the "whole" query, the database is at liberty to return rows in any order it wants. The specific order you get is a result of how looking up rows is done when using the IN operator.
On your other query you are specifying an order yourself, so the database has to honor it.