mysql running total, order by date - mysql

I have been trying to do a running total "order by date". The problem is that if you have two entries with the same date, then it shows the same total on both rows.
Table structure is something like this
sipID|Date|Amount
1|2017-11-07|2
2|2017-11-09|27
3|2017-11-07|24
So I know how to do a running total by id like this.
SELECT `sipID`,DATE_FORMAT(`Date`,'%d %M %Y') as `DateFormat`,`Amount`,
(SELECT SUM(`Amount`) FROM `salesinvoice_payments` as `Lin` WHERE `Lin`.`sipID`<=`Lout`.`sipID` && `salesinvoice_id`=115) as `Balance`
FROM `salesinvoice_payments` as `Lout`
WHERE `salesinvoice_id`=115
ORDER BY `sipID`
But I wanted it to be ordered by date ascending so I did this
SELECT `sipID`,DATE_FORMAT(`Date`,'%d %M %Y') as `DateFormat`,`Amount`,
(SELECT SUM(`Amount`) FROM `salesinvoice_payments` as `Lin` WHERE `Lin`.`Date`<=`Lout`.`Date` && `salesinvoice_id`=115) as `Balance`
FROM `salesinvoice_payments` as `Lout`
WHERE `salesinvoice_id`=115
ORDER BY `Date` ASC
Now this does work. The problem happens when you have 2 rows with the same date. What happens then is that both rows have the same running total.
eg
07 November 2017 2.00 24.00
07 November 2017 22.00 24.00
09 November 2017 3.00 27.00
What I want is this
07 November 2017 2.00 2.00
07 November 2017 22.00 24.00
09 November 2017 3.00 27.00
Is there a workaround so that I can have a proper running total, and have it ordered by date without it getting the same total on the same date?
EDIT:
#Strawberry:
I have finally worked out how sqlfiddle works, and put this for my original question.
http://www.sqlfiddle.com/#!9/c6dc75/1

You need something to separate Ammount from same day.
SQL DEMO
SELECT `sipID`,
DATE_FORMAT(`Date`,'%d %M %Y') as `DateFormat`,
`Amount`,
(SELECT SUM(`Amount`)
FROM `salesinvoice_payments` as `Lin`
WHERE `Lin`.`Date` < `Lout`.`Date`
OR (`Lin`.`Date` = `Lout`.`Date`
AND `Lin`.`sipID` <= `Lout`.`sipID`)
) as `Balance`
FROM `salesinvoice_payments` as `Lout`
ORDER BY `Date` ASC
OUTPUT

Approach using user variables: DEMO with nod to Juan for setup of tables/data
SELECT `sipID`
, DATE_FORMAT(`Date`,'%d %M %Y') as `DateFormat`
,`Amount`
,#Bal:=#Bal+`amount` as `Balance`
FROM `salesinvoice_payments` as `Lout`
CROSS JOIN (SELECT #Bal:=0) z --initializes and declares variable in select
WHERE `salesinvoice_id`=115
ORDER BY `Date`, `sipID`
Or using pagination
SELECT *
FROM (SELECT `sipID`
, DATE_FORMAT(`Date`,'%d %M %Y') as `DateFormat`
,`Amount`
,#Bal:=#Bal+`amount` as `Balance`
FROM `salesinvoice_payments` as `Lout`
CROSS JOIN (SELECT #Bal:=0) z --initializes and declares variable in select
WHERE `salesinvoice_id`=115
ORDER BY `Date`, `sipID`) Z
ORDER BY `DateFormat`, `sipID`
LIMIT 5,10; -- Retrieve rows 6-15 Skip 5 retrieve next 10.
In this approach the variables have already been resolved in set {Z} thus the user variables are not impacted by the Limit/offset.
Example using your SQL Fiddle but we would need more sample data to really see the pagination impact.

Related

Finding the difference between consecutive rows in MySQL without LAG?

For each month (except January) I would like to find the difference in quantity from the previous month.
I have a table:
Month
Qty
January
4
February
3
March
9
April
3
May
7
and I would like to return:
Month
Difference
February
-1
March
6
April
-6
May
4
I'm using an older version of MySQL, so I can't use LEAD/LAG for this.
SELECT t1.`Month`, COALESCE(t1.Qty - t2.Qty, 'Unknown') Difference
FROM table t1
LEFT JOIN table t2
ON STR_TO_DATE(CONCAT(t1.`Month`, ' 01 2021'), '%M %d %Y')
= STR_TO_DATE(CONCAT(t2.`Month`, ' 01 2021'), '%M %d %Y') + INTERVAL 1 MONTH
You can use a correlated subquery to get the previous value. If the first column is really ordered, then you can use:
select t.*, (qty - prev_qty) as difference
from (select t.*,
(select t2.qty
from t t2
where t2.month < t.month
order by t2.month desc
limit 1
) as prev_qty
from t
) t
where prev_qty is not null;
If you are really storing months as a string name, then you need to convert to something orderable:
select t.*, (qty - prev_qty) as difference
from (select t.*,
(select t2.qty
from t t2
where str_to_date(concat(t2.month, ' 1 2000', '%M %d %Y') < str_to_date(concat(t.month, ' 1 2000', '%M %d %Y')
order by str_to_date(concat(t2.month, ' 1 2000', '%M %d %Y') desc
limit 1
) as prev_qty
from t
) t
where prev_qty is not null;

Query to get records from quarter before current quarter in MySQL

I am trying to get records from quarter before current quarter in MySQL. But not able to figure out how the query will be constructed.
My MySQL table:
Here's my query to get records of current quarter (Jan 2020 to March 2020):
SELECT * FROM `customers` WHERE QUARTER(`customer_date`) = QUARTER(CURRENT_DATE)
AND YEAR(`customer_date`) = YEAR(CURRENT_DATE)
ORDER BY `customer_date` DESC
But when I am using following query to get records from quarter before current quarter i.e. records from Oct 2019 to Dec 2019, the query doesn't yield me correct result. Actually it fetches records of every quarter (Oct to Dec) of all previous years in the table:
SELECT * FROM `customers` WHERE QUARTER(`customer_date`) = QUARTER(CURRENT_DATE - INTERVAL 1 QUARTER)
ORDER BY `customer_date` DESC
I can't use YEAR in above query. If I use the year then query will fail when it will be run in the future e.g. in the quarter of Apr 2020 to Jun 2020.
How can this query be modified to get required result?
Try this will do:
select
*
from
customers
where
quarter(`customer_date`) = quarter(current_date - interval 1 quarter)
and year(customer_date) =
(case
when quarter(curdate()) > 1 then year(current_date)
else year(current_date)-1
end)
order by
`customer_date` desc
db<>fiddle

How to update Query to calc SUM or COUNT using two dates and BETWEEN?

My current query is as such:
SELECT
CAST(COUNT(`MID`) AS UNSIGNED) AS Y,
CONCAT(
LEFT(MONTHNAME(`date`),
3),
' ',
YEAR(`date`)
) AS label
FROM
`reservations`
WHERE
`MID` = 22 AND YEAR(`date`) = YEAR(CURDATE())
GROUP BY
CONCAT(
LEFT(MONTHNAME(DATE),
3),
' ',
YEAR(`date`)
),
YEAR(DATE),
MONTH(DATE)
ORDER BY
YEAR(`date`),
MONTH(`date`) ASC
It produces the following results that we use in Google Charts to show the number of reservations per month.
The issue is we are only getting the number of times a reservation is created, not the number of days between the start date (date) and the end date (dateLast).
Y label
________________
22 Feb 2019
28 Mar 2019
15 Apr 2019
3 May 2019
5 Jun 2019
2 Jul 2019
1 Aug 2019
1 Oct 2019
2 Nov 2019
9 Dec 2019
I've been trying the following update but getting an error related to the BETWEEN operator:
SELECT
CAST(COUNT(`mid`) AS UNSIGNED BETWEEN `date` AND `dateLast`) AS D, CONCAT(
LEFT(MONTHNAME(DATE),
3), ' ', YEAR(DATE) ),
CAST(COUNT(`mid`) AS UNSIGNED) AS Y,
CONCAT(
LEFT(MONTHNAME(DATE),
3),
' ',
YEAR(DATE)
) AS label
FROM
`reservations`
WHERE
`mid` = 22 AND YEAR(DATE) = YEAR(CURDATE())
GROUP BY
CONCAT(
LEFT(MONTHNAME(DATE),
3),
' ',
YEAR(DATE)
),
YEAR(DATE),
MONTH(DATE)
ORDER BY
YEAR(DATE),
MONTH(DATE) ASC
MySQL said: Documentation
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'BETWEEN date AND dateLast) AS D, CONCAT(LEFT(MONTHNAME(DATE),' at line 2
The goal is to get a SUM for all days reserved between AND including date to dateLast Note: dateLast is not counted as it is the Checkout date. Maybe this is too complex for a SQL query and should be handled in PHP as a series of sub-routines?
If you don't need to split the number of days of one reservation over multiple months, then you can just use SUM(DATEDIFF(dateLast, date))
select year(date) y, month(date) m, sum(datediff(dateLast, date)) c
from reservations
group by y, m
order by y, m
db-fiddle
If you want to split them, then I hope your version (MySQL 8+ or MariaDB 10.2+) supports recursive queries. In that case you can expand the date range to one row per day in the range and count them:
with recursive rcte as (
select date, dateLast
from reservations
where dateLast > date -- optional
union all
select rcte.date + interval 1 day, rcte.dateLast
from rcte
where rcte.date < rcte.dateLast - interval 1 day
)
select year(date) y, month(date) m, count(*) c
from rcte
group by y,m
order by y,m
db-fiddle
SQL can definitely handle this. Use the DATEDIFF function
https://www.w3schools.com/sql/func_mysql_datediff.asp

I want to show data monthwise in one sql query? Is it possible in mysql

I have a one database and saved one year data. I want to access all data in monthwise. like (01-01-2017-01-30-2017). My column type Datetime
date_table
01-01-2016
01-02-2016
02-02-2017
.....
.....
I Want to show
date_table count
01-01-2016 to 30-01-2016 5
01-02-2016 t0 28-02-2016 10
Have a derived table that returns the year and month. GROUP BY its result and count:
select y, m, count(*)
from
(
select year(date_column) y , month(date_column) m
from tablename
)
group by y, m
I don't know MySQL very well, so you'll have to format the output by yourself.
You can use mysql's built in function LAST_DAY, like this:
Just replace here "t", with your table name
SELECT CONCAT( CONCAT(mnth, '-01'), ' to ', LAST_DAY(CONCAT(mnth, '-01')) ) AS date_table, cnt FROM (
select substr(cast(date_table as CHAR), 1, 7) AS mnth, count(*) AS cnt from t
group by substr(cast(date_table as CHAR), 1, 7)
) outertable
If your Date is of type DateTime in SQL-Server
SELECT DATENAME(MONTH,TimeStamp) AS [MONTH]
, DATEPART(YY,TimeStamp) [YEAR]
, SUM(*) Count
FROM Table
WHERE TimeStamp IS NOT NULL
GROUP BY DATENAME(MONTH,TimeStamp), DATEPART(YY,TimeStamp)
Result would be like this
MONTH YEAR Count
December2015 237
October 2015 51
August 2016 0
January 2016 9
March 2016 160

Is subquery the solution to this?

Here's the table structure and some sample data:
pID.....month.....year
27 .....3 .....2008
27 .....12 .....2012
31 .....6 .....2008
99 .....1 .....2006
42 .....1 .....2009
pID is the practiceID and month and year represent the date period they've entered data for. I need to grab the number of practices that have entered data for the first time in Oct 2012, Nov 2012, Dec 2012 and so on.
I tried the following query for Oct 2012:
SELECT *
FROM
IPIPKDIS
where
practiceID NOT IN (
SELECT practiceID
from
IPIPKDIS
where
year < 2012 and month < 10
)
and year = 2012
and month = 10
and measureCatRecID = 2
ORDER BY year, month;
but it's grabbing months and year less than 10/2012.
If I run the queries isolated (not as subquery) they both work fine.
Any ideas?
This summary query will yield the first (smallest) date in the table for each value of practiceID.
SELECT practiceID,
MIN(STR_TO_DATE( CONCAT(year, ' ', month), '%Y %m')) first_date
FROM IPIPKDIS
GROUP BY practiceID
If you want to retrieve then the whole row for the first reported month, you'd do a nested query like this:
SELECT *
FROM IPIPKDIS I
JOIN (
SELECT practiceID,
MIN(STR_TO_DATE( CONCAT(year, ' ', month), '%Y %m')) first_date
FROM IPIPKDIS
GROUP BY practiceID
) first ON ( first.practiceID = I.practiceID
AND STR_TO_DATE( CONCAT(I.year, ' ', I.month), '%Y %m') = first.first_date)
The trick to the second query is to use the JOIN to extract just the first-month rows from your table. We use date arithmetic to do the date comparisons.