Combine two queries and add a new column - mysql

DB-Fiddle
CREATE TABLE sales (
id int auto_increment primary key,
category VARCHAR(255),
event_date DATE,
sent_date DATE,
sales_Product_gross VARCHAR(255),
return_Product_gross VARCHAR(255)
);
INSERT INTO sales
(category, event_date, sent_date,
sales_Product_gross, return_Product_gross
)
VALUES
("CAT_01", "2017-05-30", "2017-05-30", "500", NULL),
("CAT_01", "2017-06-05", "2017-05-30", NULL, "250"),
("CAT_01", "2018-07-08", "2018-07-08", "700", NULL),
("CAT_01", "2018-07-18", "2018-07-08", NULL, "370"),
("CAT_01", "2019-02-15", "2019-02-15", "400", NULL),
("CAT_01", "2019-03-21", "2019-02-15", NULL, "120"),
("CAT_02", "2019-04-24", "2019-04-24", "300", NULL),
("CAT_02", "2019-04-30", "2019-04-24", NULL, "145"),
("CAT_02", "2019-12-14", "2019-12-14", "900", NULL),
("CAT_02", "2019-12-28", "2019-12-14", NULL, "340"),
("CAT_03", "2020-03-09", "2020-03-09", "800", NULL),
("CAT_03", "2020-03-17", "2020-03-09", NULL, "425");
The table displays the sales and returns in different categories.
Now, I want to calculate:
a) the return_rate per month per campaign and store it in a new column called calc_type with the name monthly.
b) the return_rate on a rolling 2 YEAR basis and also store it in the new column calc_type with the name rolling.
The result should look like this:
category calc_type year month return_rate
CAT_01 rolling NULL NULL 0.445
CAT_01 monthly 2017 5 0.500
CAT_01 monthly 2018 7 0.528
CAT_01 monthly 2019 2 0.300
CAT_02 rolling NULL NULL 0.404
CAT_02 monthly 2019 4 0.480
CAT_02 monthly 2019 12 0.377
CAT_03 rolling NULL NULL 0.531
CAT_03 monthly 2020 3 0.531
I have created a query for criteria a) and for criteria b). Separately, those queries work exactly the way I need it.
Now, I tried to combine them using UNION ALL the same way it is done here:
SELECT
category,
'rolling' AS calc_type,
'NULL' AS year,
'NULL' As month,
sum(return_Product_gross) / sum(sales_Product_gross) as return_rate
FROM sales
WHERE sent_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 2 YEAR) AND CURDATE()
GROUP BY 1,2,3,4
ORDER BY 1,2,3,4;
UNION ALL
SELECT
category,
'monthly' AS calc_type,
YEAR(sent_date) AS year,
MONTH(sent_date) AS month,
sum(return_Product_gross) / sum(sales_Product_gross) as return_rate
FROM sales
WHERE sent_date BETWEEN "2017-01-01" AND CURDATE()
GROUP BY 1,2,3,4
ORDER BY 1,2,3,4;
However, now only the values for rolling are displayed in the result.
What do I need to change in my queries to get the expected result?

This query looks worked:
SELECT
category,
'rolling' AS calc_type,
'NULL' AS year,
'NULL' As month,
sum(return_Product_gross) / sum(sales_Product_gross) as return_rate
FROM sales
WHERE sent_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 2 YEAR) AND CURDATE()
GROUP BY category, year, month
UNION ALL
SELECT
category,
'monthly' AS calc_type,
YEAR(sent_date) AS year,
MONTH(sent_date) AS month,
sum(return_Product_gross) / sum(sales_Product_gross) as return_rate
FROM sales
WHERE sent_date BETWEEN "2017-01-01" AND CURDATE()
GROUP BY category, year, month
ORDER BY category, calc_type DESC, year, month;
DBFiddle

Related

Mysql query - month

I am a beginner in Mysql and I have a table like this:
create table purchase
(
purchase_ID INT primary key,
purchase_date DATE,
purchase_price INT
);
Insert into purchase values ('1', '2015-5-30', '10000');
Insert into purchase values ('2', '2016-7-30', '80000');
Insert into purchase values ('3', '2017-8-30', '50000');
Insert into purchase values ('4', '2016-10-30', '90000');
Now the question is: find which month has highest sales for the year 2016.
NOTE: consider purchase price as sales.
To find the answer for this, I tried this SQL statement:
SELECT
MAX(purchase_price) AS sales,
MONTH(purchase_date)
FROM
purchase
WHERE
CAST(purchase_date AS date) BETWEEN '2016-01-01' AND '2016-12-30'
and getting results as
sales month(purchase_date)
----------------------------
90000 7
but I am getting error in month because 10th month had highest sales not 7, can any one advise on this?
For using MAX, SUM, etc u need to do GROUP BY (aggregated query with GROUP BY)
SELECT MAX(purchase_price) as sales, MONTH(purchase_date) as month
from purchase where purchase_date between '2016-01-01' and '2016-12-30'
GROUP BY month
ORDER BY month desc
LIMIT 1
this query should work for you.
find which month has highest sales for the year 2016
SELECT *
FROM purchase
WHERE purchase_date BETWEEN '2016-01-01' AND '2016-12-30'
ORDER BY purchase_price DESC
LIMIT 1

How to get monthly average active orders

I have orders table which has the start date, end date and anticipated end date columns, I can able to get all the active work orders in month but I am looking for selected month average working orders.
I am trying to find an idea to get but unable to get, can someone please help on this?
SQL Fiddle
Updated Fiddle (Can we combine those 3 queries into single Query1+Query2-Query3 = desired count which is 7 in this case)
Updated as per the comments:
Average working means for example there are thousands of orders are in the database and some might close in the middle of the month and some might start in the start of the month some might start in the next month. So I want to know on average how many orders are working in the month.
Desired Result or Count is: 7, because 4 Orders are closed in the month and 4 are started in the month.
MySQL 5.6 Schema Setup:
CREATE TABLE `orders` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`order_num` BIGINT(20) NULL DEFAULT NULL,
`start_date` DATE NULL DEFAULT NULL,
`anticpated_end_date` DATE NULL DEFAULT NULL,
`end_date` DATE NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1
;
INSERT INTO `orders` (`order_num`, `start_date`, `anticpated_end_date`, `end_date`) VALUES
('124267', '2019-01-11', '2020-01-10', '2020-01-10'),
('464335', '2019-01-03', '2019-11-15', '2019-12-13'),
('313222', '2019-01-03', '2020-02-15', NULL),
('63356', '2019-04-12', '2019-05-15', '2019-06-13'),
('235233', '2020-01-20', '2020-11-15', NULL),
('313267', '2019-01-03', '2020-01-15', '2020-01-19'),
('123267', '2019-12-10', '2020-07-31', NULL),
('234523', '2019-12-07', '2020-10-15', NULL),
('12344', '2020-01-03', '2020-02-15', NULL),
('233523', '2019-01-03', '2020-01-02', '2020-01-02'),
('233423', '2020-01-05', '2020-03-15', NULL),
('45644', '2020-01-11', '2020-08-15', NULL),
('233723', '2019-06-03', '2020-01-05', '2020-01-05'),
('345234', '2020-02-02', '2020-02-15', NULL),
('232423', '2020-02-03', '2020-03-15', NULL);
Query 1:
SELECT order_num, start_date, anticpated_end_date, end_date
FROM orders
WHERE start_date <= date("2020-01-31")
AND
(
(
end_date IS NULL AND
(
anticpated_end_date >= date("2020-01-31") OR
anticpated_end_date BETWEEN date("2020-01-01") AND date("2020-01-31")
)
) OR
(
end_date >= date("2020-01-31") OR
end_date BETWEEN date("2020-01-01") AND date("2020-01-31")
)
);
For the first query, I find this easier to read...
SELECT order_num, start_date, anticpated_end_date, end_date
FROM orders
WHERE start_date < '2020-01-01'
AND COALESCE(end_date,anticpated_end_date) > '2020-01-31';
If you're only interested in the count of that result, then consider the following...
SELECT SUM(start_date < '2020-01-01' AND COALESCE(end_date,anticpated_end_date) > '2020-01-31')n
FROM orders;
Does that help?
I am assuming that if the end date is marked as null then it is an active order else the order is not active.
So all active orders for month of Jan would be where end date is null and the start date is on or before 31 Jan 2020.
Based o above 2 assumptions the resulting query would look like this:
select order_num, start_date, end_date, anticpated_end_date
from orders
where end_date is null
and start_date <= date("2020-01-31")
order by start_date,end_date,anticpated_end_date;

mysql: need records only if the date is there at least once each day, the date should be repeated for 4 days from the current datetime

I have a table with 6 columns: failure date, ipaddress, assettag, sid(primary key), rdl and error type.
I need a table with columns as First failure, Recent(Last) failure, ipaddress, assettag, rdl
But the records are to be there only if the date is repeated for 4 days from the current datetime. Not even one single day to be missed.
Ex: If today is 30th May, I need all the records whose failure date is there every single day--30th, 29th, 28th, 27th. If a record date is there only for two/three/one day(s)--it has to be ignored.
I can get First and Last failures using "min(date) and max(date)-group by ipaddress" but not able to get the records as per the condition--"failure (date) to be repeated for 4 days from current datetime"
select min(date), max(date), ipaddress, assettag, rdl
from flashinglist.response
where ((DATE_FORMAT((date_sub(NOW(), interval 24 hour)), '%y-%m-%d')) in
(select group_concat((DATE_FORMAT(date,'%y-%m-%d')) separator ', ')
from flashinglist.response group by ipaddress)
and (DATE_FORMAT((date_sub(NOW(), interval 48 hour)), '%y-%m-%d')) in
(select group_concat((DATE_FORMAT(date,'%y-%m-%d')) separator ', ')
from flashinglist.response group by ipaddress)
and (DATE_FORMAT((date_sub(NOW(), interval 72 hour)), '%y-%m-%d')) in
(select group_concat((DATE_FORMAT(date,'%y-%m-%d')) separator ', ')
from flashinglist.response group by ipaddress)
and (DATE_FORMAT((date_sub(NOW(), interval 96 hour)), '%y-%m-%d')) in
(select group_concat((DATE_FORMAT(date,'%y-%m-%d')) separator ', ')
from flashinglist.response group by ipaddress) )
order by max(date) desc
The above query should work as I am concatenating all dates group by IP and checking through 'IN' condition, but it doesn't work, not able to figure out why. (used 'date_format' to find only date instead of timestamp)
Below is the schema and sample data:
CREATE TABLE `response` (
`date` varchar(50) NOT NULL,
`ipaddress` varchar(16) NOT NULL,
`assettag` varchar(200) NOT NULL,
`sid` int(4) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`rdl` varchar(30) NOT NULL,
`errortype` int(2) NOT NULL)
ENGINE=InnoDB DEFAULT CHARSET=latin1;
Sample data:
INSERT INTO `response` (`date`, `ipaddress`, `assettag`, `sid`, `rdl`, `errortype`) VALUES
('2019-05-31 09:46:10.878', '123.34.45.67', 'fresh', 483, '13234', 1),
('2019-05-30 19:46:11.578', '123.34.45.67', 'fresh', 490, '13234', 1),
('2019-05-29 14:30:11.577', '123.34.45.67', 'fresh', 496, '13234', 1),
('2019-05-28 17:23:11.573', '123.34.45.67', 'fresh', 499, '13234', 1),
('2019-05-27 22:32:11.550', '123.34.45.67', 'fresh', 503, '13234', 1),
('2019-05-29 12:54:11.571', '457.673.768.24', 'store', 560, '9297', 1),
('2019-05-31 08:46:11.569', '457.673.768.24', 'store', 565, '9297', 1),
('2019-05-28 10:45:11.566', '457.673.768.24', 'store', 567, '9297', 1),
('2019-05-30 20:16:11.566', '457.673.768.24', 'store', 569, '9297', 1),
('2019-05-29 23:46:11.234', '140.232.546.74', 'sample', 580, '6076', 1),
('2019-05-31 09:26:11.562', '140.232.546.74', 'sample', 581, '6076', 1),
('2019-05-30 19:34:16.533', '140.232.546.74', 'sample', 583, '6076', 1);
COMMIT;
Please change values according to today's date and the last 4 days.
My output should return First failure, Recent(Last) failure, ipaddress, assettag, rdl-- with the above sample data, it has to show IP records: 123.34.45.67 and 457.673.768.24 with corresponding max and min dates with in the range of 1 to 96 hours (4 days) only.
IP- 140.232.546.74 should not appear as it is the failure is not repeated for 4 days (28th date is missing). Hope this clears my question.
Count the number of different dates in the result, and test if this is the required number.
SELECT min(date) AS mindate, max(date) AS maxdate, date, ipaddress, assettag, rdl
FROM flashinglist.response
WHERE date < DATE_SUB(NOW(), interval 1 hour)
AND date > date_sub(NOW(), interval 96 hour)
GROUP BY ipaddress
ORDER BY mindate DESC
HAVING COUNT(DISTINCT DATE(date)) = DATE_SUB(maxdate, mindate) + 1
You also shouldn't have these lines:
AND (date > date_sub(NOW(), interval 24 hour) )
AND (date > date_sub(NOW(), interval 48 hour))
AND (date > date_sub(NOW(), interval 72 hour))
since they will exclude rows that are more than 1 day old.

How to sum columns from two tables if the month match and group by month

Currently I achieved to do it with a single table with this query:
SELECT EXTRACT(MONTH FROM date) as month, SUM(total) as total FROM invoices GROUP BY month ORDER BY month ASC
But now I'm going crazy trying to return the same result from two columns, let's say total1 and total2, and group by month, if there is no invoice in a month in one of the columns the result should be cero.
Tables structure and expected result:
invoices payments
date date
total income
month totalInvoices totalPayments
1 10005 8017
2 756335 5019
3 541005 8017
4 34243 8870
How do I achieve this? Any suggestions?
You need a third element to the query structure which provides a complete list of all relevant years/months. This might be an existing table or a subquery, but the overall query will follow the structure outlined below:
CREATE TABLE invoices
(`id` int, `invdate` datetime, `invtotal` numeric);
INSERT INTO invoices
(`id`, `invdate`, `invtotal`)
VALUES
(1, '2017-01-21 00:00:00', 12.45);
CREATE TABLE payments
(`id` int, `paydate` datetime, `paytotal` numeric);
INSERT INTO payments
(`id`, `paydate`, `paytotal`)
VALUES
(1, '2017-02-21 00:00:00', 12.45);
select
ym.year, ym.month, inv.invtotal, pay.paytotal
from (
SELECT
EXTRACT(YEAR FROM invdate) as year
, EXTRACT(MONTH FROM invdate) as month
FROM invoices
UNION
SELECT
EXTRACT(YEAR FROM paydate) as year
, EXTRACT(MONTH FROM paydate) as month
FROM payments
) ym
left join (
SELECT
EXTRACT(YEAR FROM invdate) as year
, EXTRACT(MONTH FROM invdate) as month
, SUM(invtotal) as invtotal
FROM invoices
GROUP BY year, month
) inv on ym.year = inv.year and ym.month = inv.month
left join (
SELECT
EXTRACT(YEAR FROM paydate) as year
, EXTRACT(MONTH FROM paydate) as month
, SUM(paytotal) as paytotal
FROM payments
GROUP BY year, month
) pay on ym.year = pay.year and ym.month = pay.month;
year | month | invtotal | paytotal
-----|-------|----------|--------|
2017 | 1 | 12 | null |
2017 | 2 | null | 12 |
In my example the "third element" is the subquery ym but this may be too inefficient for your actual query, but it should server to identify how to co-ordinate data over disparate time ranges.
dbfiddle here

Want to calculate leave days month wise in mysql

Scenario is if Employee apply for leave: From Date is "2016-03-30" and To Date is "2016-04-02" so Output will be "In 3rd month leave days should be 2" and "In 4th month leave days should be 1".
I have Table:
UserID FromDate ToDate LeaveDuration
------------------------------------------------------
0001 20/03/2016 21/03/2016 1
0001 30/03/2016 02/04/2016 2
In 2nd record 2 days should be consider in 3rd month and 1 day should be consider in 4th month.
I tried below query:
select sum(datediff(ToDate,FromDate)) as Total
from wp_ag_assign_leave
where UserId=18
and LeaveType="Carry Forward Leave"
and (EXTRACT(MONTH FROM CURDATE())=EXTRACT(MONTH FROM FromDate)
OR EXTRACT(MONTH FROM CURDATE())=EXTRACT(MONTH FROM ToDate))
Please Help me to solve it
you may want to precise some dates usind e.g date_add but here's what I've done :
select month,
sum(duration) as 'LeaveDays'
from (
select if(month(FromDate)=month(ToDate),month(FromDate),'other') as 'month',
if(month(FromDate)=month(ToDate),datediff(Todate, FromDate),'other') as 'duration'
from wp_ag_assign_leave
UNION
select if(month(FromDate)!=month(ToDate),month(FromDate),'other') as 'month',
if(month(FromDate)!=month(ToDate),datediff(last_day(FromDate),FromDate),'other') as 'duration'
from wp_ag_assign_leave
UNION
select if(month(FromDate)!=month(ToDate),month(ToDate),'other') as 'month',
if(month(FromDate)!=month(ToDate),dateDiff(ToDate,last_day(FromDate)),'other') as 'duration'
from wp_ag_assign_leave
) as parseMonths
where month!='other'
group by month
order by month;
The 3 SELECTin the UNION statement :
- 1 the dates are in the same month, simple difference
- 2 the dates are NOT in the same month : 1st month's part
- 2 the dates are NOT in the same month : 2nd month's part
As per scenario calculate month and year wise leave days
select user_id,ymonth,
sum(duration) as 'LeaveDays'
from (
select user_id,if(EXTRACT(YEAR_MONTH FROM leave_from)=EXTRACT(YEAR_MONTH FROM leave_to),EXTRACT(YEAR_MONTH FROM leave_from),'other') as 'ymonth',
if(EXTRACT(YEAR_MONTH FROM leave_from)=EXTRACT(YEAR_MONTH FROM leave_to),datediff(leave_to, leave_from)+1,'other') as 'duration'
from leave_application
UNION ALL
select user_id, if(EXTRACT(YEAR_MONTH FROM leave_from)!=EXTRACT(YEAR_MONTH FROM leave_to),EXTRACT(YEAR_MONTH FROM leave_from),'other') as 'ymonth',
if(EXTRACT(YEAR_MONTH FROM leave_from)!=EXTRACT(YEAR_MONTH FROM leave_to),datediff(last_day(leave_from),leave_from)+1,'other') as 'duration'
from leave_application
UNION ALL
select user_id, if(EXTRACT(YEAR_MONTH FROM leave_from)!=EXTRACT(YEAR_MONTH FROM leave_to),EXTRACT(YEAR_MONTH FROM leave_to),'other') as 'ymonth',
if(EXTRACT(YEAR_MONTH FROM leave_from)!=EXTRACT(YEAR_MONTH FROM leave_to),dateDiff(leave_to,last_day(leave_from)),'other') as 'duration'
from leave_application
) as parseMonths
where ymonth!='other'
group by ymonth
order by ymonth