Order by month giving reverse order in Mysql - mysql

I'm trying to order a mysql query according to the month name but it is ordering in reverse order .I have tried both the ASC and DESC order but not working!This is what i'm getting :
order_amount month_number
370.245 Dec
0.01 Aug
0.02 July
0.01 May
2 Apr
3 Mar
4 Feb
5 Jan
This is the query:
select sum(amnt) as order_amount,month_number from orders where paid =1 GROUP BY month_number ORDER BY MONTH(month_number) ASC
This is a sample table 'order' on which i'm running query
order_amount month_number paid
370.245 Jan 1
0.01 Aug 1
0.02 July 1
0.01 Apr 1
2 May 0
3 Mar 1
4 Feb 0
5 Nov 0

month_number() is a lousy name for a string name for the month. That said, your attempts will not work, because month() takes a date, not a string representation. The best way is probably just to use case:
order by (case when month_number = 'Jan' then 1
when month_number = 'Feb' then 2
. . .
when month_number = 'Dec' then 12
end)
I would strongly suggest you include a date or actual month number in the table. And, rename month_number to something like month_name.

According to your sample, you've got 'Dec', 'Aug' and so on in your month_number field.
How is month(month_number) supposed to work if you don't pass a valid date type? if you pass some random text you'll just get NULL and can't order by NULL
http://sqlfiddle.com/#!2/3a774d/3/0
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_month

SELECT * FROM my_table;
+-------+
| month |
+-------+
| Apr |
| Aug |
| Dec |
| Feb |
| Jan |
| Jul |
| Jun |
| Mar |
| May |
| Nov |
| Oct |
| Sep |
+-------+
SELECT * FROM my_table ORDER BY STR_TO_DATE(CONCAT('2014-',month,'-01'),'%Y-%b-%d');
+-------+
| month |
+-------+
| Jan |
| Feb |
| Mar |
| Apr |
| May |
| Jun |
| Jul |
| Aug |
| Sep |
| Oct |
| Nov |
| Dec |
+-------+
... or something like that

Related

How to write an SQL query to calculate the average for three consecutive values?

I have a table like this
userID time NoOfVisits
1 2014 50
2 2015 60
3 2016 70
4 2017 80
5 2018 90
6 2019 100
I need to write a sql query which will print time and average of past 3 years NoOfVisits for a particular site.
output should be as
userID time NoOfVisits
1 2014 50.0000
2 2015 55.0000
3 2016 60.0000
4 2017 70.0000
5 2018 80.0000
6 2019 90.0000
Explanation :
For user Id 6 (80+90+100)/3=90.0000
Please help me to solve this problem.
You can use a cumulative average, available in MySQL 8+:
select t.*,
avg(visits) over (order by time rows between 2 preceding and current row) as avg_visits_3
from t;
Assuming there are no gaps between the years (like your sample data), you can self join the table and group by userid, time to get the average:
select
t.userid, t.time, avg(tt.noofvisits) NoOfVisits
from tablename t inner join tablename tt
on tt.time between t.time - 2 and t.time
group by t.userid, t.time
See the demo.
Results:
| userid | time | NoOfVisits |
| ------ | ---- | ---------- |
| 1 | 2014 | 50 |
| 2 | 2015 | 55 |
| 3 | 2016 | 60 |
| 4 | 2017 | 70 |
| 5 | 2018 | 80 |
| 6 | 2019 | 90 |

mySQL creating a complex query/ view/ report

I have 3 tables as below :
1/ Table 'order_fruit'
-------------------------------------------------------------
id_fruit_table | fruit_name | order_quantity | delivery_date
---------------+------------+----------------+---------------
1 |mango | 10 | 04 2018
2 |mango | 5 | 05 2018
3 |banana | 20 | 04 2018
4 |pineapple | 9 | 06 2018
2/ Table 'stock_fruit'
---------------------------------------------------
id_stock | fruit_name_stock | stock_quantity
--------------+-------------------+----------------
1 | mango | 5
2 | pineapple | 10
3/ Table 'pipeline'
--------------------------------------------------------------------
id_pipeline | fruit_pipeline | receive_date | pipeline_quantity
--------------+------------------+--------------+-------------------
1 | mango | 04 2018 | 5
2. | banana | 05 2018 | 15
How can i make a query/ view/ report like below:
-----------------------------------------------------------------------------------
fruit | 04 2018 | 05 2018 | 06 2018
---------+---------------------------------------------------------------+---------
| order_qty-| stock-| pipeline | order_qty- | stock- | pipeline | ...
---------+-----------+-------+----------+------------+--------+----------+---------
mango | 10 | 5 | 5 | 5 | 0 | 0 | ...
banana | 20 | 0 | 0 | 0 | 0 | 15 | ...
pineapple| 0 | 10 | 0 | 0 | 10 | 0 | ...
Here opening stock for 05 2018 = 04 2018(stock + pipeline - order_qty)
Opening stock for 06 2018 = 05 2018(stock + pipeline - order_qty)
Try to use the following way
-- the first query returns all distinct dates
SELECT delivery_date oper_date
FROM order_fruit
UNION
SELECT receive_date
FROM pipeline
And you can use this information to generate the second query
-- the second query is generated using information about dates from the first query
SELECT
fruit_name
,SUM(stock_quantity) stock_quantity
-- 04 2018
,SUM(CASE WHEN oper_date='04 2018' THEN order_quantity END) order_quantity_04_2018
,SUM(CASE WHEN oper_date='04 2018' THEN pipeline_quantity END) pipeline_quantity_04_2018
-- 05 2018
,SUM(CASE WHEN oper_date='05 2018' THEN order_quantity END) order_quantity_05_2018
,SUM(CASE WHEN oper_date='05 2018' THEN pipeline_quantity END) pipeline_quantity_05_2018
-- 06 2018
,SUM(CASE WHEN oper_date='06 2018' THEN order_quantity END) order_quantity_06_2018
,SUM(CASE WHEN oper_date='06 2018' THEN pipeline_quantity END) pipeline_quantity_06_2018
-- ...
FROM
(
SELECT delivery_date oper_date,fruit_name,order_quantity,NULL stock_quantity,NULL pipeline_quantity
FROM order_fruit
UNION ALL
SELECT NULL,fruit_name_stock,NULL,stock_quantity,NULL
FROM stock_fruit
UNION ALL
SELECT receive_date,fruit_pipeline,NULL,NULL,pipeline_quantity
FROM pipeline
) q
GROUP BY fruit_name
SQL Fiddle - http://www.sqlfiddle.com/#!9/ceb1680/2

MySQL Complex Check with dates

I have a table called Offers in which I have several offers:
ID | List Name | Arrival | Depart | Price
1 | Plus | 12 August | 18 August | $ 100.00
2 | Plus | 19 August | 25 August | $ 120.00
3 | Plus | 26 August | 1 September | $ 80.00
4 | Weekend | 11 August | 13 August | $ 50.00
5 | Weekend | 18 August | 20 August | $ 60.00
6 | Weekend | 25 August | 27 August | $ 40.00
Then I have a guest in my hotel which has a check-in and check-out date.
In need to find all the offers with the same List Name that cover all the days of my vacation's guest (from check-in date to check-out date).
Example
If my guest spends his time in my hotel from the 13th of August to the 20th of August I need to be returned only ids 1 and 2.
If my guest spends his time in my hotel from the 13th of August to the 27th of August I need to be returned only ids 1, 2, and 3. That's because the ids 6 and 7 cover only weekend and not all the days between check-in and check-out dates.
If my guest spends his time in my hotel from the 18th of August to the 20th of August I need to be returned only ids 1, 2 and 5.
You are looking for logic like this:
select o.*
from offers o
where o.arrival <= $arrival and o.depart >= $depart;
$arrival and $depart are the dates for your guest.
You need to do something like this :
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE offers
(`ID` int, `Arrival` date, `Depart` date, `Price` float)
;
INSERT INTO offers
(`ID`, `Arrival`, `Depart`, `Price`)
VALUES
(1, '2016-08-12', '2016-08-18', 100.00),
(2, '2016-08-19', '2016-08-25', 120.00),
(3, '2016-08-26', '2016-09-01', 80.00),
(4, '2016-08-11', '2016-08-13', 50.00),
(5, '2016-08-18', '2016-08-20', 60.00),
(6, '2016-08-25', '2016-08-27', 40.00)
;
Query 1:
select *
from offers
where (((arrival >= '2016-08-13' and arrival <= '2016-08-20') or
(depart >= '2016-08-13' and depart <= '2016-08-20'))
and datediff(depart,arrival) = 6)
or
(arrival = '2016-08-13' and depart = '2016-08-20'
and datediff(depart,arrival) = 2)
Results:
| ID | Arrival | Depart | Price |
|----|--------------------------|--------------------------|-------|
| 1 | August, 12 2016 00:00:00 | August, 18 2016 00:00:00 | 100 |
| 2 | August, 19 2016 00:00:00 | August, 25 2016 00:00:00 | 120 |
Query 2:
select *
from offers
where (((arrival >= '2016-08-13' and arrival <= '2016-08-27') or
(depart >= '2016-08-13' and depart <= '2016-08-27'))
and datediff(depart,arrival) = 6)
or
(arrival = '2016-08-13' and depart = '2016-08-27'
and datediff(depart,arrival) = 2)
Results:
| ID | Arrival | Depart | Price |
|----|--------------------------|-----------------------------|-------|
| 1 | August, 12 2016 00:00:00 | August, 18 2016 00:00:00 | 100 |
| 2 | August, 19 2016 00:00:00 | August, 25 2016 00:00:00 | 120 |
| 3 | August, 26 2016 00:00:00 | September, 01 2016 00:00:00 | 80 |
Query 3:
select *
from offers
where (((arrival >= '2016-08-18' and arrival <= '2016-08-20') or
(depart >= '2016-08-18' and depart <= '2016-08-20'))
and datediff(depart,arrival) = 6)
or
(arrival = '2016-08-18' and depart = '2016-08-20'
and datediff(depart,arrival) = 2)
Results:
| ID | Arrival | Depart | Price |
|----|--------------------------|--------------------------|-------|
| 1 | August, 12 2016 00:00:00 | August, 18 2016 00:00:00 | 100 |
| 2 | August, 19 2016 00:00:00 | August, 25 2016 00:00:00 | 120 |
| 5 | August, 18 2016 00:00:00 | August, 20 2016 00:00:00 | 60 |

MySQL `SUM` with `GROUP BY` is missing data in results

I have a database with a table containing information on some images, each row containing a createdAt date and a viewCount. The data ranges from September 2014 until today (July 2016). I want to get a monthly sum of the amount of views across all images for the month
When I run the query
SELECT YEAR(createdAt), MONTH(createdAt), SUM(viewCount)
FROM Images
GROUP BY MONTH(createdAt);
I'm only returned 12 rows with results between September 2014 and August 2015
Year | Month | Views
-------------------
2014 | 9 | 1452
2014 | 10 | 279
2014 | 11 | 34428
2014 | 12 | 4763
2015 | 1 | 2826
2015 | 2 | 777
2015 | 3 | 568
2015 | 4 | 1309
2015 | 5 | 46744
2015 | 6 | 1541
2015 | 7 | 8160
2015 | 8 | 91
If I add a date restraint it will give me the latest data, but again only 12 rows
SELECT YEAR(createdAt), MONTH(createdAt), SUM(viewCount)
FROM Images WHERE createdAt > DATE('2015-08-01 00:00:00')
GROUP BY MONTH(createdAt);
Year | Month | Views
--------------------
2015 | 8 | 981
2015 | 9 | 1031
2015 | 10 | 2566
2015 | 11 | 3325
2015 | 12 | 411
2016 | 1 | 2140
2016 | 2 | 710
2016 | 3 | 714
2016 | 4 | 1985
2016 | 5 | 426
2016 | 6 | 119
2016 | 7 | 81
I do realise that since it's July the second query stops there as that's where the data ends, but why does the first query not return all the results?
Group by year/month:
SELECT YEAR(createdAt), MONTH(createdAt), SUM(viewCount)
FROM Images
--WHERE createdAt > DATE('2015-08-01 00:00:00')
GROUP BY YEAR(createdAt), MONTH(createdAt);
Related Group by clause in mySQL and postgreSQL, why the error in postgreSQL?
Keep in mind that from MySQL 5.7.6+ your initial query may not even work because of only_full_group_by which is set by default.
You can simply add Year to you group by
SELECT YEAR(createdAt), MONTH(createdAt), SUM(viewCount)
FROM Images
GROUP BY YEAR(createdAt), MONTH(createdAt)
ORDER BY YEAR(createdAt), MONTH(createdAt)

How to get difference of two rows in same column

I have to find the difference in the value of a single column of table as current row value-previous row value for some 'n' number of rows in one column and also I don't have ID to use as reference for increment
date: box_count : total_no_of_boxes_used
1/12/12 2 2
2/12/12 8 6
3/12/12 14 6
I have box_count column and I am trying to get total_no_of_boxes_used column.
Please help me.
Thanks in advance
Given your records are sequential by date.....
SQLFIDDLE DEMO
Query:
select a.date, a.bc, case when (a.bc-b.bc) is null then a.bc else a.bc-b.bc end tot
from tt a
left join
tt b
on a.date > b.date
group by b.date
;
Results:
DATE BC TOT
December, 01 2012 00:00:00+0000 2 2
December, 02 2012 00:00:00+0000 8 6
December, 03 2012 00:00:00+0000 14 6
December, 04 2012 00:00:00+0000 23 9
One way to do this, is using a correlated subquery like so:
SELECT
t1.`date`,
t1.box_count,
t1.box_count -
IFNULL((SELECT t2.box_count
FROM table1 t2
WHERE t2.`date` < t1.`date`
ORDER BY t2.`date` DESC
LIMIT 1),
0 ) AS total_no_of_boxes_used
FROM table1 t1;
SQL Fiddle Demo
This will give you:
| DATE | BOX_COUNT | TOTAL_NO_OF_BOXES_USED |
------------------------------------------------------------------------
| January, 12 2012 00:00:00+0000 | 2 | 2 |
| February, 12 2012 00:00:00+0000 | 8 | 6 |
| March, 12 2012 00:00:00+0000 | 14 | 6 |
Try this:
SELECT date,
(box_count - #diff) total_no_of_boxes_used,
(#diff:=box_count) box_count
FROM table1, (SELECT #diff:=0) A;
Check this SQL FIDDLE DEMO
OUTPUT
| DATE | TOTAL_NO_OF_BOXES_USED | BOX_COUNT |
------------------------------------------------------------------------
| January, 12 2012 00:00:00+0000 | 2 | 2 |
| February, 12 2012 00:00:00+0000 | 6 | 8 |
| March, 12 2012 00:00:00+0000 | 6 | 14 |