How to calculate the initial Stock with MySql - mysql

I'm trying to find a way to calculate the initial stock by the number of weeks.
I'm have just managed to calculate the 'in' and 'out' of stock between the weeks 10 and 20 with this request.
Can someone give me the full request to calculate the final stock and the initial stock.
SELECT
`week` ,
SUM(case
when `week` between 10 AND 20 and `etat` =1
then 1
else 0
end) AS inn
,
SUM(case
when `week` between 10 AND 20 and `etat` =2
then 1
else 0
end) AS out
FROM fait_stock f
where 1=1
group by `week`
having `week` between 10 AND 20
EDIT
I want to calculate the stock of the previous weeks (initial stock that means weeks<10) for example week 10 I have 5. week 11 It should be 5+(stock of week 11). Week 12 it should be 5+(stock of week 11)+(stock of week 12) the same for others weeks.

First of all - you can write your query much shorter:
SELECT
`week` ,
SUM(IF(`etat`=1, 1, 0)) AS inn,
SUM(IF(`etat`=2, 1, 0)) AS `out`
FROM fait_stock
WHERE `week` BETWEEN 10 AND 20
GROUP BY `week`
If you now join it with itself (with a small modification, if you want the sums of weeks < 10), you can calculate the sums for all weeks that are smaller or equal than the given week:
SELECT f1.`week`, SUM(f2.inn) AS inn, SUM(f2.`out`) AS `out`
FROM (
SELECT
`week` ,
SUM(IF(`etat`=1, 1, 0)) AS inn,
SUM(IF(`etat`=2, 1, 0)) AS `out`
FROM fait_stock
WHERE `week` BETWEEN 10 AND 20
GROUP BY `week`
) AS f1
JOIN (
SELECT
`week` ,
SUM(IF(`etat`=1, 1, 0)) AS inn,
SUM(IF(`etat`=2, 1, 0)) AS `out`
FROM fait_stock
WHERE `week` BETWEEN 1 AND 20
GROUP BY `week`
) AS f2 ON f2.`week` <= f1.`week`
GROUP BY f1.`week`

Related

MySQL get different SUMs based on dates

I'm trying to create a Sql query where I can sums for 4 different date range.
SELECT t.TenantID, t.TenantFName, t.TenantLName, u.UnitName,
TotalDebit, HousingDebit, TotalCredit, HousingCredit
FROM Tenants t
JOIN Units u ON t.UnitID = u.UnitID
LEFT JOIN (
Select
TenantID,
SUM(CASE WHEN TransactionTypeID = 1 AND ChargeTypeID != 6 THEN TransactionAmount ELSE 0 END) AS TotalDebit,
From TenantTransactions
Where TenantTransactionDate BETWEEN /* Here is my issue */
Group By TenantID
) sums ON sums.TenantID = t.TenantID
Where t.Prospect = 2
AND t.PropertyID = 10
I am trying to return 4 sums:
For the last 30 days
For last 30-60 days
For last 60-90 days
Greater than 90 days ago
Does it make sense?
Thanks
You're looking for totals based on the age of the transaction. We can get that by subtracting the transaction date from today to get a result in days:
datediff(now(), TenantTransactionDate)
You want to group that into period by 30 days, so we use integer division to get a period:
datediff(now(), TenantTransactionDate) DIV 30
And lastly, you want everything over 90 days grouped together:
if(datediff(now(), TenantTransactionDate)<90, datediff(now(), TenantTransactionDate) DIV 30, 3)
This last expression returns a value of 0, 1, 2 or 3. We can use that to group the transactions, and total them:
SELECT TenantID,
sum(TransactionAmount) as totalDebit,
if(datediff(now(), TenantTransactionDate)<90, datediff(now(), TenantTransactionDate) DIV 30, 3) as period
FROM TenantTransactions
where TransactionTypeID=1 and chargeTypeID != 6
group by tenantID, period
order by tenantID, period
Now you should be able to plug that back into your original query, and sort them:
SELECT t.TenantID, t.TenantFName, t.TenantLName, u.UnitName,
TotalDebit, HousingDebit, TotalCredit, HousingCredit
FROM Tenants t
JOIN Units u ON t.UnitID = u.UnitID
LEFT JOIN (
SELECT TenantID,
sum(TransactionAmount) as totalDebit,
if(datediff(now(), TenantTransactionDate)<90, datediff(now(), TenantTransactionDate) DIV 30, 3) as period
FROM TenantTransactions
where TransactionTypeID=1 and chargeTypeID != 6
group by tenantID, period
) sums ON sums.TenantID = t.TenantID
Where t.Prospect = 2
AND t.PropertyID = 10
order by t.tenantID, sums.period

Get week over week data

I have a table as follows
CREATE TABLE messages (
id int(10) UNSIGNED AUTO_INCREMENT NOT NULL,
messagetext text NOT NULL,
created_at timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY(id)
)
What I would like to do is to get two weeks of data, the current week and the previous week, ordered by days. For example how many messages were created on Sunday, Monday, Tuesday,Wednesday.... for this week and the last week.
I do have a query as follows
SELECT
COUNT(id) AS 'Count'
FROM
'messages'
WHERE
(WEEK(created_at) = WEEK(NOW()))
GROUP BY
WEEKDAY(created_at)
ORDER BY
week(created_at) ASC,
weekday(created_at) ASC
but I don't know how to sort it day wise. For example the query above will list me how many did i get today or yesterday but that is not what what I want. What I would like to have is to get the count day wise as well as week wise.
Here is what I would like to have
Please let me know if i clear enough with the situation that I am facing.
Update:
For more information , please see Juan's question below
If the current days are less that 14 days , in that case, the script should return the count for the days that are in the previous week , not the week before the previous week. Here is how Juan explained (imagine today is friday. if you count 14 day back you get this week monday to friday. previous week monday to sunday... and prev prev week friday to sunday. And not sure if that is the result you want)
With Regards
Gagan
Use conditional SUM
SELECT week(created_at) week_id,
SUM( IF(weekday(created_at) = 0, 1, 0) ) as monday,
SUM( IF(weekday(created_at) = 1, 1, 0) ) as tuesday,
SUM( IF(weekday(created_at) = 2, 1, 0) ) as wednesday,
SUM( IF(weekday(created_at) = 3, 1, 0) ) as thursday,
SUM( IF(weekday(created_at) = 4, 1, 0) ) as friday,
SUM( IF(weekday(created_at) = 5, 1, 0) ) as saturday,
SUM( IF(weekday(created_at) = 6, 1, 0) ) as sunday
FROM 'messages'
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 14 DAY)
AND ( week_id = WEEK( NOW() )
OR week_id = WEEK( DATE_SUB(NOW(), INTERVAL 7 DAY)
)
GROUP BY
week_id
ORDER BY
week_id
Im going to send a big guess. But did you try something like this?
SELECT
week(created_at) week_id,
weekday(created_at) weekday_id,
COUNT(id) AS 'Count'
FROM
'messages'
WHERE
week_id = WEEK( NOW() )
OR week_id = WEEK( DATE_SUB(NOW(), INTERVAL 7 DAY) )
GROUP BY
week_id, weekday_id
ORDER BY
week_id, weekday_id

Last date in quarter MySQL

I have a table with some dates. I need a query which will return the max (last) date from this table and last date of quarter this max date belongs to.
So for data i table
ID| EDATE
--+----------
1|2014-03-06
2|2014-10-12
this query should return 2014-10-12 and 2014-12-31.
As I understand you want the last day of the quarter, so 31 March, 30 June, 30 Sept, 31 Dec? So you can use the answer from Gordon Linoff and adjust it to do that.
You only need a case statement on month(date) and concat that with the year.
http://dev.mysql.com/doc/refman/5.1/de/control-flow-functions.html
str_to_date(
concat(
year(edate),
(case
when month(edate) in (1, 2, 3) then '-03-31'
when month(edate) in (4, 5, 6) then '-06-30'
when month(edate) in (7, 8, 9) then '-09-30'
else '-12-31'
end)
),
'%Y-%m-%d'
)
Getting the day of the last quarter for the date is a bit yucky, but possible. Here is a sort of brute force solution:
select edate,
str_to_date(concat(year(edate), '-', 1 + floor((month(edate) - 1)/ 3)) * 3, '-',
(case when month(edate) in (1, 2, 3, 10, 11, 12) then 31 else 30 end)),
'%Y-%m-%d'
)
from table t
order by edate desc
limit 1;
Here is a SQL Fiddle that demonstrates it.
You can use LAST_DAY to select the last day of a specific month depending on where your quarters end you may have to change the 3,6,9,12 to different months.
select t1.max_date,
(
case
when month(max_date) <= 3
then last_day(concat(year(max_date),'-3-1'))
when month(max_date) <= 6
then last_day(concat(year(max_date),'-6-1'))
when month(max_date) <= 9
then last_day(concat(year(max_date),'-9-1'))
else last_day(concat(year(max_date),'-12-1'))
end
) last_quarter_day
from (
select max(EDATE) max_date from myTable
) t1
I found the simplest answer:
SELECT MAKEDATE(YEAR(edate),1)
+ INTERVAL QUARTER(edate) QUARTER
- INTERVAL 1 DAY
This query takes the first day of year, adds quarters to it and subtracts 1 day to get the last day in wanted quarter. So the required query should look like:
SELECT MAX(edate),
MAKEDATE(YEAR(MAX(edate)),1)
+ INTERVAL QUARTER(MAX(edate)) QUARTER
- INTERVAL 1 DAY
FROM table

How to group by time slot between two dates

I have a question that make me feel silly !
I have to do some stats on the use of my apps.
I have a table call : customer_point
id int(11) auto_increment
id_customer int(11)
type_point int(11)
date timestamp CURRENT_TIMESTAMP
I want to make this request for the entire month (with a row for each night ;) ) :
SELECT COUNT( id_customer ) , type_point, date(date)
FROM customer_point
WHERE date BETWEEN "2014-06-01 20:00:00" AND "2014-06-02 10:00:00"
GROUP BY type_point, date;
I nearly sure that i miss a crusial point but i can't find witch one.
Thank you very much for reading me !
Bye,
edit :
Sample :
INSERT INTO `customer_point` ( `id` , `id_customer` , `type_point`, `date` )
VALUES ( '', '15', '1', '2014-06-01 22:50:00'), ( '', '15', '1', '2014-06-01 23:52:00'), ( '', '15', '1', '2014-06-02 9:50:00'), ( '', '15', '1', '2014-06-30 22:50:00'), ( '', '15', '1', '2014-06-30 23:52:00'), ( '', '15', '1', '2014-07-01 02:50:00', ( '', '15', '1', '2014-07-01 09:50:00');
result :
1, 3, 2014-06-01
1, 4, 2014-06-30
I hope this will help everbody to understand my probleme :/
If you just want coutns of the actual data, check the date is within the range you are interested in and that the time is at night (ie, greater than 8pm or less than 10am, if would seem from your SQL):-
SELECT type_point, date(customer_point.date) AS aDate, COUNT( id_customer )
FROM customer_point
WHERE DATE(customer_point.date) BETWEEN "2014-06-01" AND "2014-06-30"
AND TIME(customer_point.date) >= '20:00:00' OR TIME(customer_point.date) <= '10:00:00'
GROUP BY type_point, aDate;
To get a row per day, irrespective of whether there is any data that day(ie, a count of zero it no data) then you need to generate a list of dates and then LEFT JOIN your data to it.
Something like this:-
SELECT sub0.aDate, type_point, COUNT( id_customer )
FROM
(
SELECT DATE_ADD('2014-06-01', INTERVAL units.i + tens.i * 10 DAY) AS aDate
FROM
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
CROSS JOIN
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3) tens
) sub0
LEFT OUTER JOIN customer_point
ON sub0.aDate = date(customer_point.date)
WHERE sub0.aDate BETWEEN "2014-06-01" AND "2014-06-30"
GROUP BY sub0.aDate, type_point;
You would also probably need to generate a list of type_point values.
EDIT - to go with the updated question, can you just subtract 10 hours from the date / time. So 10am on the 1st July becomes midnight on the 30th June?
SELECT type_point, date(DATE_ADD(customer_point.date, INTERVAL -10 HOUR)) AS aDate, COUNT( id_customer )
FROM customer_point
WHERE DATE(DATE_ADD(customer_point.date, INTERVAL -10 HOUR)) BETWEEN "2014-06-01" AND "2014-06-30"
AND TIME(customer_point.date) >= '20:00:00' OR TIME(customer_point.date) <= '10:00:00'
GROUP BY type_point, aDate;
SQL fiddle:-
http://www.sqlfiddle.com/#!2/ddc95/2
The issue with this is whether items from before 10am on the 1st of June count as dates for May or for June?
Using mysql you even could do
WHERE date LIKE "2014-06-%"
Edit: You need exactly from 20:00 and then you have to take in account the first day of the next mounth until the 22:00...
Ok, then just substract those 20 hours to the date:
SELECT DATE_SUB(column, INTERVAL 20 HOUR)....
Finally:
SELECT COUNT( id_customer ) , type_point, DATE_SUB(date, INTERVAL 20 HOUR) as mydate
FROM customer_point
WHERE mydate LIKE "2014-06-%"
GROUP BY type_point, date;

showing previous and current month data in table using mysql

I am trying to show three different figures of the same column In a mysql query, I would like to keep one month static: April, so it would be a case like this I want to show The current month, the previous month and the static month of the year I'm working with, in this case let us stick with 2012
Example
Tablename:payment
id , pay_date, amount
1 2012-02-12 1000
2 2012-03-11 780
3 2012-04-15 890
4 2012-05-12 1200
5 2012-06-12 1890
6 2012-07-12 1350
7 2012-08-12 1450
So what I want to do is show the column amount for the month of April as I said I want to keep that row static: 890, the current month lets say the current month is August:1450 and the previous month amount which would be July:1350: so the final result would be something like this:
april_amount current_month_amount previous_month_amount
890 1450 1350
However I'm stuck here:
select amount as april_amount
from payment
where monthname(pay_date) LIKE 'April'
and year(pay_date) LIKE 2012
I hope the question is written clear enough, and thanks alot for the help much appreciated.
If the results can be rows instead of columns:
SELECT MONTHNAME(pay_date), amount FROM payment
WHERE pay_date BETWEEN '2012-04-01'
AND '2012-04-30'
OR pay_date BETWEEN CURRENT_DATE
- INTERVAL DAYOFMONTH(CURRENT_DATE) - 1 DAY
AND LAST_DAY(CURRENT_DATE)
OR pay_date BETWEEN CURRENT_DATE
- INTERVAL DAYOFMONTH(CURRENT_DATE) - 1 DAY
- INTERVAL 1 MONTH
AND LAST_DAY(CURRENT_DATE - INTERVAL 1 MONTH)
See it on sqlfiddle.
I might be way off here. But try:
select top 1
p.amount, c.amount, n.amount
from payment c
inner join payment p ON p.pay_date < c.pay_date
inner join payment n ON n.pay_date > c.pay_date
where monthname(c.paydate) LIKE 'April'
and year(c.pay_date) LIKE 2012
order by p.pay_date DESC, n.pay_date ASC
EDIT, I didnt read your question properly. I was going for previous, current, and next month. 1 minute and I'll try again.
select top 1
p.amount AS april_amount, c.amount AS current_month_amount, n.amount AS previous_month_amount
from payment c
inner join payment p ON monthname(p.pay_date) = 'April' AND year(p.pay_date) = 2012
inner join payment n ON n.pay_date > c.pay_date
where monthname(c.paydate) = monthname(curdate())
and year(c.pay_date) = year(curdate())
order by n.pay_date ASC
This assumes there is only 1 entry per month.
Ok, so i haven't written in mysql for a while. here is what worked for your example data:
select
p.amount AS april_amount, c.amount AS current_month_amount, n.amount AS previous_month_amount
from payment AS c
inner join payment AS p ON monthname(p.pay_date) LIKE 'April' AND year(p.pay_date) LIKE 2012
inner join payment AS n ON n.pay_date < c.pay_date
where monthname(c.pay_date) LIKE monthname(curdate())
and year(c.pay_date) LIKE year(curdate())
order by n.pay_date DESC
limit 1
the previous month table joined is counterintuitively named n, but this works. I verified it in a WAMP install.
To handle aggregates per month you can use subselects. Performance may suffer on very large tables (millions of rows or more).
SELECT SUM( a.amount ) AS april_amount,
(
SELECT SUM( c.amount )
FROM payment c
WHERE MONTH( c.pay_date ) = MONTH( CURDATE( ) )
) AS current_month_amount,
(
SELECT SUM( p.amount )
FROM payment p
WHERE MONTH( p.pay_date ) = MONTH( CURDATE( ) - INTERVAL 1
MONTH )
) AS previous_month_amount
FROM payment a
WHERE MONTHNAME( a.pay_date ) = 'April'
AND YEAR( a.pay_date ) =2012