MYSQL query - getting totals by month - mysql

http://sqlfiddle.com/#!2/6a6b1
The scheme is given above.. all I want to do is get the results as the total of sales/month... the user will enter a start date and end date and I can generate (in PHP) all the month and years for those dates. For example, if I want to know the total number of "sales" for 12 months, I know I can run 12 individual queries with start and end dates, but I want to run only one query where the result will look like:
Month numofsale
January - 2
Feb-1
March - 23
Apr - 10
and so on...
or just a list of sales without the months, I can then pair it to the array of months generated in the PHP ...any ideas...
Edit/schema and data pasted from sqlfiddle.com:
CREATE TABLE IF NOT EXISTS `lead_activity2` (
`lead_activity_id` int(11) NOT NULL AUTO_INCREMENT,
`sp_id` int(11) NOT NULL,
`act_date` datetime NOT NULL,
`act_name` varchar(255) NOT NULL,
PRIMARY KEY (`lead_activity_id`),
KEY `act_date` (`act_date`),
KEY `act_name` (`act_name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
INSERT INTO `lead_activity2` (`lead_activity_id`, `sp_id`, `act_date`, `act_name`) VALUES
(1, 5, '2012-10-16 16:05:29', 'sale'),
(2, 5, '2012-10-16 16:05:29', 'search'),
(3, 5, '2012-10-16 16:05:29', 'sale'),
(4, 5, '2012-10-17 16:05:29', 'DNC'),
(5, 5, '2012-10-17 16:05:29', 'sale'),
(6, 5, '2012-09-16 16:05:30', 'SCB'),
(7, 5, '2012-09-16 16:05:30', 'sale'),
(8, 5, '2012-08-16 16:05:30', 'sale'),
(9, 5,'2012-08-16 16:05:30', 'sale'),
(10, 5, '2012-07-16 16:05:30', 'sale');

SELECT DATE_FORMAT(date, "%m-%Y") AS Month, SUM(numofsale)
FROM <table_name>
WHERE <where-cond>
GROUP BY DATE_FORMAT(date, "%m-%Y")
Check following in your fiddle demo it works for me (remove where clause for testing)
SELECT DATE_FORMAT(act_date, "%m-%Y") AS Month, COUNT(*)
FROM lead_activity2
WHERE <where-cond-here> AND act_name='sale'
GROUP BY DATE_FORMAT(act_date, "%m-%Y")
It returns following result
MONTH COUNT(*)
07-2012 1
08-2012 2
09-2012 1
10-2012 3

You can try query as given below
select SUM(`SP_ID`) AS `Total` , DATE_FORMAT(act_date, "%M") AS Month, Month(`ACT_DATE`) AS `Month_number` from `lead_activity2` WHERE `ACT_DATE` BETWEEN '2012-05-01' AND '2012-12-17' group by Month(`ACT_DATE`)
Here 2012-05-01 and 2012-12-17 are date input from form. and It will be return you the sum of sales for particular month if exist in database.
thanks

Try this query -
SELECT
MONTH(act_date) month, COUNT(*)
FROM
lead_activity2
WHERE
YEAR(act_date) = 2012 AND act_name = 'sale'
GROUP BY
month
Check WHERE condition if it is OK for you - act_name = 'sale'.
If you want to output month names, then use MONTHNAME() function instead of MONTH().

SELECT YEAR(act_date), MONTH(act_date), COUNT(*)
FROM lead_activity2
GROUP BY YEAR(act_date), MONTH(act_date)
For getting data by month or any other data based on column you have to add GROUP BY.
You can add many columns or calculated values to GROUP BY.
I assume that "num of sales" means count of rows.

Sometimes you might want the month names as Jan, Feb, Mar .... Dec possibly for a Chart likeFusionChart
SELECT DATE_FORMAT(date, "%M") AS Month, SUM(numofsale)
FROM <Table_name>
GROUP BY DATE_FORMAT(date, "%M")
Results would look like this on table
MONTH COUNT(*)
Jul 1
Aug 2
SEP 1
OCT 3

Related

How to get summary data for every months in mysql

I want to count the number of items sold(item_count) every month for every item,
--
-- Table structure for table `sales`
--
CREATE TABLE `sales` (
`id` int(11) NOT NULL,
`item_id` int(11) NOT NULL,
`date` date NOT NULL,
`item_count` int(11) NOT NULL,
`amount` float NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `sales`
--
INSERT INTO `sales` (`id`, `item_id`, `date`, `item_count`, `amount`) VALUES
(1, 1, '2018-01-15', 11, 110),
(2, 2, '2018-01-21', 5, 1000),
(3, 1, '2018-02-02', 7, 700),
(4, 2, '2018-02-11', 3, 3000);
I have tried this SQL, but it's not showing the data correctly.
SELECT `sales`.`item_id`,
(CASE WHEN MONTH(sales.date)=1 THEN sum(sales.item_count) ELSE NULL END) as JAN,
(case when MONTH(sales.date)=2 THEN sum(sales.item_count) ELSE NULL END) as FEB
FROM sales WHERE 1
GROUP BY sales.item_id
ORDER BY sales.item_id
This is my expected result,
item_id JAN FEB
1 11 7
2 5 3
I am getting this,
item_id JAN FEB
1 18 NULL
2 8 NULL
Here is an immediate fix to your query. You need to sum over a CASE expression, rather than the other way around.
SELECT
s.item_id,
SUM(CASE WHEN MONTH(s.date) = 1 THEN s.item_count END) AS JAN,
SUM(CASE WHEN MONTH(s.date) = 2 THEN s.item_count END) AS FEB
FROM sales s
GROUP BY
s.item_id
ORDER BY
s.item_id;
But the potential problem with this query is that in order to support more months, you need to add more columns. Also, if you want to cover mulitple years, then this approach also might not scale. Assuming you only have a few items, here is another way to do this:
SELECT
DATE_FORMAT(date, '%Y-%m') AS ym,
SUM(CASE WHEN item_id = 1 THEN item_count END) AS item1_total,
SUM(CASE WHEN item_id = 2 THEN item_count END) AS item2_total
FROM sales
GROUP BY
DATE_FORMAT(date, '%Y-%m');
This would generate output looking something like:
ym item1_total item2_total
2018-01 11 5
2018-02 7 3
Which version you use depends on how many months your report requires versus how many items might appear in your data.

Calculating product purchases in a Financial Year | SQL Server

I would like to find out product purchases for 2 financial years (FY16-17 & FY17-18).
To go about it:
OwnerID: 101, the first purchase is in 2014 with 3 purchases in FY17-18.
OwnerID: 102, the first purchase is in 2011 with 1 purchase in FY16-17, 1 purchase in FY17-18.
OwnerID: 103, the first purchase is in 2017 however should not be considered as he's a new customer with only 1 purchase in FY17-18. (i.e. first purchase not considered if new customer)
OwnerID: 104, the first purchase is in 2016 but made 3 more purchases in FY16-17.
Code:
CREATE TABLE Test
(
OwnerID INT,
ProductID VARCHAR(255),
PurchaseDate DATE
);
INSERT INTO Test (OwnerID, ProductID, PurchaseDate)
VALUES (101, 'P2', '2014-04-03'), (101, 'P9', '2017-08-09'),
(101, 'P11', '2017-10-05'), (101, 'P12', '2018-01-15'),
(102, 'P1', '2011-06-02'), (102, 'P3', '2016-06-03'),
(102, 'P10', '2017-09-01'),
(103, 'P8', '2017-06-23'),
(104, 'P4', '2016-12-17'), (104, 'P5', '2016-12-18'),
(104, 'P6', '2016-12-19'), (104, 'P7', '2016-12-20');
Desired output:
FY16-17 FY17-18
-----------------
5 4
I tried the below query to fetch records that aren't first occurrence and there by fetching the count within financial years:
SELECT *
FROM
(SELECT
ROW_NUMBER() OVER(PARTITION BY OwnerID ORDER BY PurchaseDate) AS OCCURANCE
FROM Test
GROUP BY OwnerID, PurchaseDate)
WHERE
OCCURANCE <> 1
However it throws an error:
Msg 102, Level 15, State 1, Line 5
Incorrect syntax near ')'.
The subquery needs to have an alias - try this:
SELECT *
FROM
(SELECT
ROW_NUMBER() OVER(PARTITION BY OwnerID ORDER BY PurchaseDate) AS OCCURRENCE
FROM Test
GROUP BY OwnerID, PurchaseDate) subQry
WHERE
subQry.OCCURRENCE <> 1
I am using IIF to separate the two fiscal years and subquery to filter out those with only one purchase
SELECT SUM(IIF(PurchaseDate >= '2016-04-01' AND PurchaseDate < '2017-04-01',1,0)) AS 'FY16-17',
SUM(IIF(PurchaseDate >= '2017-04-01' AND PurchaseDate < '2018-04-01',1,0)) AS 'FY17-18'
FROM test t1
JOIN (SELECT ownerID, COUNT(*) count
FROM test
GROUP BY ownerID) t2 on t1.ownerID = t2.ownerID
WHERE t2.count > 1

Mysql select just one row per day in interval

I have a mysql DB with multiple that contains data like this.
http://sqlfiddle.com/#!9/f084c
CREATE TABLE `datos` (
`id` int(11) NOT NULL,
`fecha` datetime NOT NULL,
`temperatura` tinyint(4) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `datos` (`id`, `fecha`, `temperatura`) VALUES
(1874, '2017-05-20 01:56:40', 20),
(1875, '2017-05-20 01:56:51', 20),
(1876, '2017-06-18 23:32:49', 17),
(1877, '2017-06-18 23:34:50', 17),
(1878, '2017-06-18 23:36:51', 17),
(1879, '2017-06-18 23:38:52', 17),
(1880, '2017-06-18 23:46:02', 16),
(1881, '2017-06-18 23:47:12', 17),
(1882, '2017-06-22 01:06:27', 21);
I want to select just one value of a day during a 30 day interval, to have a result like this
2017-06-22 01:06:27 21
2017-06-18 23:47:12 17
2017-05-20 01:56:51 20
I have selected the entire interval using
SELECT * FROM `datos` WHERE fecha >= '2017-06-22 01:06:27' - INTERVAL 30 DAY
But i have not managed to just select one value per day instead of all of them.
Would appreciate the help
Based on the desired result you listed, it looks like you want maximum fecha for each day.
select date(fecha), max(fecha)
from datos
group by date(fecha)
This results in the following:
2017-06-22 2017-06-22 01:06:27
2017-06-18 2017-06-18 23:47:12
2017-05-20 2017-05-20 01:56:51
By treating the above query as a table and joining it back to the datos table you can get the complete record: id, fecha, and temperatura which had the maximum fecha each day.
select d1.*
from datos d1,
(select date(fecha), max(fecha) as max_fecha
from datos
group by date(fecha) ) d2
where d1.fecha = d2.max_fecha
and d1.fecha >= '2017-06-22 01:06:27' - INTERVAL 30 DAY
Resulting in the following:
1875 2017-05-20 2017-05-20 01:56:51 20
1881 2017-06-18 2017-06-18 23:47:12 17
1882 2017-06-22 2017-06-22 01:06:27 21
Note I initially solved in Oracle since I do not have access to a mysql database, but I believe I correctly altered the queries to work in mysql.
select a.*
from datos a
left outer join datos b
on substr(a.fecha,1,10) = substr(b.fecha,1,10) and a.id < b.id
where b.id is null
You can manipulate your conditions of matching to select whatever property of the rows you want to prioritize.

SQL Query Issue - Picking the minimum time when there is a maximum number

SQL God...I need some help!
I have a data table that has a route_complete_percentage column and a created_at column.
I need two pieces of data:
the time stamp (within created_at column) when the route_complete_percentage is at its minimum but not zero
the time stamp (within created_at column) when the route_complete_percentage is at its maximum, it might be 100% or not, but when its at its highest.
Here is the kicker, there might be multiple time stamps for the highest route completion column. For example,
Example Table
I have multiple values when the route_completion_percentage is at its maximum, but I need the minimum time stamp value.
Here is the query so far...but the two time stamps are the same.
SELECT
A.fc,
A.plan_id,
A.route_id,
mintime.first_scan AS First_Batch_Scan,
min(route_complete_percentage),
maxtime.last_scan AS Last_Batch_Scan,
max(route_complete_percentage)
FROM
(SELECT
fc,
plan_id,
route_id,
route_complete_percentage,
CONCAT(plan_id, '-', route_id) AS JOINKEY
FROM
houdini_ops.BATCHINATOR_SCAN_LOGS_V2
WHERE
fc <> ''
AND order_id <> 'Can\'t find order'
AND source = 'scan'
AND created_at > DATE_ADD(CURDATE(), INTERVAL - 3 DAY)) A
LEFT JOIN
(SELECT
l.fc,
l.route_id,
l.plan_id,
CONCAT(l.plan_id, '-', l.route_id) AS JOINKEY,
CASE
WHEN MIN(route_complete_percentage) THEN CONVERT_TZ(l.created_at, 'UTC', s.time_zone)
END AS first_scan
FROM
houdini_ops.BATCHINATOR_SCAN_LOGS_V2 l
JOIN houdini_ops.O_SERVICE_AREA_ATTRIBUTES s ON l.fc = s.default_station_code
WHERE
l.fc <> ''
AND l.order_id <> 'Can\'t find order'
AND l.source = 'scan'
AND l.created_at > DATE_ADD(CURDATE(), INTERVAL - 3 DAY)
GROUP BY fc , plan_id , route_id) mintime ON A.JOINKEY = mintime.JOINKEY
LEFT JOIN
(SELECT
l.fc,
l.route_id,
l.plan_id,
CONCAT(l.plan_id, '-', l.route_id) AS JOINKEY,
CASE
WHEN MAX(route_complete_percentage) THEN CONVERT_TZ(l.created_at, 'UTC', s.time_zone)
END AS last_scan
FROM
houdini_ops.BATCHINATOR_SCAN_LOGS_V2 l
JOIN houdini_ops.O_SERVICE_AREA_ATTRIBUTES s ON l.fc = s.default_station_code
WHERE
l.fc <> ''
AND l.order_id <> 'Can\'t find order'
AND l.source = 'scan'
AND l.created_at > DATE_ADD(CURDATE(), INTERVAL - 3 DAY)
GROUP BY fc , plan_id , route_id) maxtime ON mintime.JOINKEY = maxtime.JOINKEY
GROUP BY fc , plan_id , route_id
I don't want to meddle with the rest of your query. Here is something that will do what it sounds like you need. There's sample data included. -- I interpreted your blank values as nulls from your sample data.
Basically, what you are looking for is the Minimum created_at value, inside each of the route_complete_percentage groups. So I treated route_complete_percentage as a group identifier. But you only care about two of the groups, so I identify those groups first in the cte, and use them to filter the aggregate query.
if object_id('tempdb.dbo.#Data') is not null drop table #Data
go
create table #Data (
route_complete_percentage int,
created_at datetime
)
insert into #Data (route_complete_percentage, created_at)
values
(0, '20170531 19:58'),
(1, null),
(2, null),
(3, null),
(4, null),
(5, null),
(6, null),
(7, null),
(80, null),
(90, null),
(100, '20170531 20:10'),
(100, '20170531 20:12'),
(100, '20170531 20:15')
;with cteMinMax(min_route_complete_percentage, max_route_complete_percentage) as (
select
min(route_complete_percentage),
max(route_complete_percentage)
from #Data D
-- This ensures the condition that you don't get the timestamp for 0
where D.route_complete_percentage > 0
)
select
route_complete_percentage,
min_created_at = min(created_at)
from #Data D
join cteMinMax MM on D.route_complete_percentage in (MM.min_route_complete_percentage, MM.max_route_complete_percentage)
group by route_complete_percentage

How to sort the the sql table considering the month an year column

I have a year column that contains things string value like 2015,2014, 2013, 2012, etc. A month column that displays string value like January, Feburary,...December. I need to run a select that sort the table considering the both Year and month column. Can anyone provide some input? Is the any system procedures to do it easily.
I want the output based on the Year and Month descending Order.
You can do something like:
order by cast(year as int) desc
,case when month = 'January' then 1
when month = 'February' then 2
....
when month = 'December' then 12
end desc
Try this
ORDER BY CAST(month+year AS DATE) DESC
Try like this
DECLARE #table TABLE
(
year VARCHAR(10),
month VARCHAR(20)
)
INSERT INTO #table
VALUES ('2015',
'January'),
('2015',
'March'),
('2015',
'February'),
('2015',
'April'),
('2015',
'May'),
('2014',
'January'),
('2014',
'February'),
('2014',
'March'),
('2014',
'May'),
('2014',
'April'),
('2016',
'January'),
('2016',
'February'),
('2016',
'March'),
('2016',
'May'),
('2016',
'April')
SELECT *
FROM #table
ORDER BY CONVERT(INT, year) desc,
Datepart(mm, Cast(month + ' 1900' AS DATETIME)) desc
You need to translate the month name into number for using a translation reference table and store values
jan-1,feb-2,march-3 like wise
Then try
SELECT * FROM tblName ORDER BY yearField DESC, monthField DESC