Counting payment from date range in MySQL - php

I want to count payment within selected date, but i can't figure it out how to do it.
Here is the example data from the my table
id starts_from payment_per_day
=======================================
1 2012-01-01 10,000.00
2 2012-01-15 10,500.00
3 2012-02-01 11,000.00
4 2012-02-15 11,500.00
5 2012-03-01 12,000.00
How do i count total payment from 2012-01-21 to 2012-02-20 ?
The total payment should be 338,500
from 2012-01-21 to 2012-01-31 = 11 days * 10,500
from 2012-02-01 to 2012-02-14 = 14 days * 11,000
from 2012-02-15 to 2012-02-20 = 6 days * 11,500
But if i do :
SELECT SUM(payment_per_day) as total FROM table
WHERE starts_from BETWEEN '2012-01-21' AND '2012-02-20'
the result is only 22,500
Any ideas ?

SELECT SUM(payment_per_day) as total FROM table
WHERE starts_from BETWEEN '2012-01-21' AND '2012-02-20';

I would first expand the range into the list of dates, then use the following query:
SELECT SUM(p1.payment_per_day)
FROM dates d
INNER JOIN payments p1 ON p1.starts_from <= d.date
LEFT JOIN payments p2 ON p2.starts_from <= d.date
AND p2.starts_from > p1.starts_from
WHERE p2.id IS NULL
You could obtain the list from the range with the help of a numbers table, like this:
SELECT DATE_ADD(#date_from, INTERVAL num DAY)
FROM numbers
WHERE num BETWEEN 0 AND DATEDIFF(#date_to, #date_from)
A numbers table is a thing worth having as it can be useful in many situations, so consider providing yourself with one. Here's a very simple script to create and initialise a numbers table:
CREATE TABLE numbers AS SELECT 0 AS num;
SET #ofs = (SELECT COUNT(*) FROM numbers); INSERT INTO numbers SELECT #ofs + num FROM numbers;
SET #ofs = (SELECT COUNT(*) FROM numbers); INSERT INTO numbers SELECT #ofs + num FROM numbers;
SET #ofs = (SELECT COUNT(*) FROM numbers); INSERT INTO numbers SELECT #ofs + num FROM numbers;
… /* repeat as necessary, each line doubles the number of rows in the table */
But, of course, you can use a loop instead.
Here's my complete testing environment on SQL Fiddle (for anyone to play with).

It seems that it is almost impossible to do query like that, counting total each day payment within selected date.
So i work around by selecting data from all starts_from dates until <= 2012-02-20 and then picking last starts_from date which is less than 2012-01-21 (that is 2012-01-15) in order to get payment_per_day 10,500.00
Thank you for viewing my question :)

Related

get monthwise row count from datewise data in mysql

I have two tables:
table 1.a
id--entry_date-amount
============================
2---2016-04-14--$400
3---2016-04-14--$400
4----2017-07-14--$200
5---2017-07-14--$500
6---2017-05-14--$600
7----2017-06-18--$100
table 2.b
id--entry_date
===========================
2---2016-04-14--$230
3---2016-04-14--$230
4----2017-07-14--$567
5---2017-07-14--$600
6---2017-05-14--$560
7----2017-06-18--$90
8---2016-04-14--$100
from the two tables how can i get count with montwise
my desired result:
month_name--total(count form table a)--total(count form table b)--amount(table a)--amount(table b)
========================================================
April,16-----------2-------------------3---$800-$500
May,17-----------1-------------------1 --$600--$700
June,17-----------2-------------------2--$100--$800
July,17-----------2-------------------2---$700-$400
this is the demo data.
I want to show data from two tables in a single query month wise.
How can i do this?
I tried:
SELECT MONTHNAME(r.entry_date),r.a_total FROM(
SELECT
IFNULL((SELECT COUNT(tr.id) AS amount FROM a AS tr WHERE MONTH(tr.entry_date)=MONTH(t.entry_date)),0) AS a_total
,t.entry_date
FROM(SELECT tr.id,tr.entry_date
FROM a AS tr
WHERE DATE(tr.entry_date) BETWEEN '2017-07-01' AND '2018-06-30') t
GROUP BY MONTH(t.entry_date)) r
But takes 58 seconds for simple query. How can i make this in a simple query?
You can get the counts and sum from each table individually, then use UNION to combine the two result sets into one result set. Something like this :
SELECT Month_name,
SUM(aCount) AS aCount,
SUM(bCount) AS bCount,
SUM(aAmount) AS aAmount,
SUM(bAmount) AS bAmount
FROM
(
SELECT
MONTHNAME(a.entry_date) AS Month_name,
COUNT(a.id) AS aCount,
0 AS bCount,
SUM(a.amount) AS aAmount,
0 AS bAmount
FROM a
GROUP BY MONTHNAME(a.entry_date)
UNION ALL
SELECT
MONTHNAME(b.entry_date) AS Month_name,
0 AS aCount,
COUNT(b.id) AS bCount,
0 AS aAmount,
SUM(b.amount) AS bAmount
FROM b
GROUP BY MONTHNAME(b.entry_date)
) AS t
GROUP BY Month_Name;
live demo
user9131497 has a good design for the big picture. However, I would suggest stuff like this for handling the dates:
SELECT DATE_FORMAT(entry_date, "%M,%y") AS 'Month',
COUNT(*) AS 'aCount'
FROM a
GROUP BY LEFT(entry_date, 7) -- eg, "2017-03"
Try that to see what I mean.
Note that this will work beyond a year. Or did you need January values from all years to be combined?? -- That's what your solution and user9131497's will do. Mine keeps them separate.

How to calculate difference between values coming from the same row in mysql

I am trying to calculate the difference of values list coming from a database.
I would like to achieve it using php or mysql, but I do not know how to proceed.
I have a table named player_scores. One of its rows contains the goals scored.
Ex.
pl_date pl_scores
03/11/2014 18
02/11/2014 15
01/11/2014 10
I would like to echo the difference between the goals scored during the matches played in different dates.
Ex:
pl_date pl_scores diff
03/11/2014 18 +3
02/11/2014 15 +5
01/11/2014 10 no diff
How can I obtain the desired result?
You seem to want to compare a score against the score on a previous row.
Possibly simplest if done using a a sub query that gets the max pl_date that is less than the pl_date for the current row, then joining the results of that sub query back against the player_scores table to get the details for each date:-
SELECT ps1.pl_date, ps1.pl_scores, IF(ps2.pl_date IS NULL OR ps1.pl_scores = ps1.pl_scores, 'no diff', ps1.pl_scores - ps1.pl_scores) AS diff
FROM
(
SELECT ps1.pl_date, MAX(ps2.pl_date) prev_date
FROM player_scores ps1
LEFT OUTER JOIN player_scores ps2
ON ps1.pl_date > ps2.pl_date
GROUP BY ps1.pl_date
) sub0
INNER JOIN player_scores ps1
ON sub0.pl_date = ps1.pl_date
LEFT OUTER JOIN player_scores ps2
ON sub0.prev_date = ps2.pl_date
There are potentially other ways to do this (for example, using variables to work through the results of an ordered sub query, comparing each row with the value stored in the variable for the previous row)
SELECT score FROM TABLE WHERE DATE = TheDateYouWant
$score = $data['score'];
SELECT score FROM TABLE WHERE date = dateYouWant
$difference = $score - $data['score'];
Something like this?
You could use two queries, one to get the value to use in the comparison (in the example below is the smaller number of scores) and the second one to get the records with a dedicated column with the difference:
SELECT MIN(pl_scores);
SELECT pl_date, pl_scores, (pl_scores - minScore) as diff FROM player_scores;
Or, using a transaction (one query execution php side):
START TRANSACTION;
SELECT MIN(Importo) FROM Transazione INTO #min;
SELECT Importo, (Importo - #min) as diff FROM Transazione;
select *,
coalesce(
(SELECT concat(IF(t1.pl_scores>t2.pl_scores,'+',''),(t1.pl_scores-t2.pl_scores))
FROM tableX t2 WHERE t2.pl_date<t1.pl_date ORDER BY t2.pl_date DESC LIMIT 1)
, 'no data' ) as diff
FROM tableX t1
WHERE 1
order by t1.pl_date DESC

mysql select 2 tables and order by 1 of them by date (more close to the current time)

This is my problem.
table ns_leagues:
id name
1 League 1
2 League 2
3 League 3
table ns_upcoming:
upID league date
1 1 1410390000
2 2 1411990200
3 3 1412010000
I have this 2 columns and I want to select the leagues from table ns_leagues and order by the row from the ns_upcoming with the date more close to the current time.
I tried several ways but nothings is working so far.
FAIL:
SELECT id
FROM ns_leagues
WHERE id in (
SELECT league
FROM ns_upcoming
WHERE date<='".$now."'
ORDER BY date ASC
SELECT DISTINCT id
from ns_leagues a
LEFT JOIN ns_upcoming v ON a.id = v.league AND v.date<= '".$now."'
ORDER BY v.date ASC
CURRENT:
SELECT * FROM ".PREFIX."leagues ORDER BY id DESC
This is what I have right now (on the right side: PROXIMOS PARTIDOS): http://www.nuno-silva.pt/jobs/mark/index.php
"En vivo" means that date >= time(); and it's not finished.
The times are countdowns for the match.
I need to order the leagues by date (selecting for that the row with the closest date to time(); from column date of table ns_upcoming of the selected league)
Could you give me a help on this one please?
You'd need to sort by the time DIFFERENCE between "now" and the match's time, e.g.
SELECT ...
...
ORDER BY DATEDIFF(ns_upcoming.date, curdate())

Get variance and standard deviation of two numbers in two different rows/columns with sqlite / PHP

I have a SQLite Database with the following structure:
rowid ID startTimestamp endTimestamp subject
1 00:50:c2:63:10:1a 1000 1090 entrance
2 00:50:c2:63:10:1a 1100 1270 entrance
3 00:50:c2:63:10:1a 1300 1310 door1
4 00:50:c2:63:10:1a 1370 1400 entrance
.
.
.
I have prepared a sqlfiddle here: http://sqlfiddle.com/#!2/fe8c6/2
With this SQL-Query i can get the average differences between the endTime and the startTime between one row and the following row, sorted by subject and ID:
SELECT
id,
( MAX(endtimestamp) - MIN(startTimestamp)
- SUM(endtimestamp-startTimestamp)
) / (COUNT(*)-1) AS averageDifference
FROM
table1
WHERE ID = '00:50:c2:63:10:1a'
AND subject = 'entrance'
GROUP BY id;
My problem: To calcute the average value is no problem, that does this query. But how can i
get the standard deviation and the variance of this values?
First finding the time differences of interest by joining the table to itself and grouping by ID, then finding the averages, variances as V(x) = E(x^2) - (E(x))^2 and standard deviation as sqrt(V)gives
SELECT ID, AVG(diff) AS average,
AVG(diff*diff) - AVG(diff)*AVG(diff) AS variance,
SQRT(AVG(diff*diff) - AVG(diff)*AVG(diff)) AS stdev
FROM
(SELECT t1.id, t1.endTimestamp,
min(t2.startTimeStamp) - t1.endTimestamp AS diff
FROM table1 t1
INNER JOIN table1 t2
ON t2.ID = t1.ID AND t2.subject = t1.subject
AND t2.startTimestamp > t1.startTimestamp -- consider only later startTimestamps
WHERE t1.subject = 'entrance'
GROUP BY t1.id, t1.endTimestamp) AS diffs
GROUP BY ID
For formulas that are more complex than simple summation, you have to compute the actual difference values for each record by lookin up the corresponding next start times, like this:
SELECT (SELECT MIN(startTimestamp)
FROM table1 AS next
WHERE next.startTimestamp > table1.startTimestamp
AND ID = '...'
) - endTimestamp AS timeDifference
FROM table1
WHERE nextStartTimestamp IS NOT NULL
AND ID = '...'
Then you can use all the difference values to do the calculations:
SELECT SUM(timeDifference) / COUNT(*) AS average,
AVG(timeDifference) AS moreEfficientAverage,
SUM(timeDifference * timeDifference) / COUNT(*) -
AVG(timeDifference) * AVG(timeDifference) AS variance
FROM (SELECT (SELECT MIN(startTimestamp)
FROM table1 AS next
WHERE next.startTimestamp > table1.startTimestamp
AND next.ID = '...'
) - endTimestamp AS timeDifference
FROM table1
WHERE nextStartTimestamp IS NOT NULL
AND ID = '...')
A number of points:
Your formula for the mean is wrong the correct formula is SUM(endtimestamp-starttimestamp)/COUNT(endtimestamp). I have no idea why you have the MIN/MAX terms. COUNT(*) will count NULL rows and will give the wrong result.
SQLlite has an avg function which finds the mean.
The formula for the variance is SUM((endtimestamp-starttimestamp)*(endtimestamp-starttimestamp)) - AVG(endtimestamp-starttimestamp)*AVG(endtimestamp-starttimestamp)
The standard deviation is the square root of the variance.
In response to the question authors comment, in order to compute the variance the start and end times must be paired with each other through a self join.
Becuase of the absence of a row_number function in SQL lite this is a little inelegant.
SELECT id,
AVG(startTimestamp-endTimestamp) as mean,
SUM((startTimestamp-endTimestamp)^2) - AVG(startTimestamp-endTimestamp)^2 as variance,
SQRT(SUM((startTimestamp-endTimestamp)^2) - AVG(startTimestamp-endTimestamp)^2) as stDev
FROM
(SELECT
t1.id,
t1.endTimestamp,
MIN(t2.startTimestamp) as starttimestamp
FROM table1 t1
INNER JOIN
table1 t2 ON t1.endTimestamp<=t2.startTimestamp
GROUP BY t1.id, t1.endTimestamp) t
GROUP BY id;
See SQL Fiddle

finding the maximum value of a field of a MySQL query result

I have this Query :
select
id_re_usr,
year(time) as AYear,
DAYOFYEAR(time) as ADay,
DATE_FORMAT(time, "%m-%d-%y") as date,
count(*) as TotalPerDay
from numrequest
where id_re_usr = "u1"
group by id_re_usr, AYear, ADay
order by AYear, ADay
it outputs something like
date TotalPerDay
------------------------
01-01-87 1
01-09-12 5
02-09-12 17
03-09-12 1
how can I find the maximum TotalPerDay without changing the current output by using php or changing the query.
I tried to do this and it works
$max=0;
while($row=mysql_fetch_array($results)){
if($max<$row['TotalPerDay']){ $max= $row['TotalPerDay'];}
}
but isn't there a direct way to do it?
if modifying the query the output should be
date TotalPerDay max
----------------------------------------
01-01-87 1 17
01-09-12 5 17
02-09-12 17 17
03-09-12 1 17
Join it to a second query of just the max count.. The inner-most queries on a per day basis (for the given user) a set of rows on count grouped per day. From that, the next outer does a select MAX() from that set to find and get only one record representing the highest day count... Since it will always return a single row, and joined to the original numRequest table it will be a Cartesian, but no problem since its only one record and you want that value on every returned row anyhow.
select
id_re_usr,
year(time) as AYear,
DAYOFYEAR(time) as ADay,
DATE_FORMAT(time, "%m-%d-%y") as date,
count(*) as TotalPerDay,
HighestCount.Max1 as HighestOneDayCount
from
numrequest,
( select max( CountsByDate.DayCount ) Max1
from ( select count(*) as DayCount
from numrequests nr
where nr.id_re_usr = "u1"
group by date( nr.time )) CountsByDate
) HighestCount
where
id_re_usr = "u1"
group by
id_re_usr,
AYear,
ADay
order by
AYear,
ADay

Categories