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;
Related
I am trying to solve this. table has cycle and date column, i wanna add one more column as end date with interval of 100 days from current date and wanna display cycle, start_date, end_date as an output.
i have tried this
select cycle, min(start) as startt, max(start) as endd
from cy
group by cycle ;
however no luck till now.
its MYSQL DB latest version.
CREATE TABLE table1 (
`cycle` INTEGER,
`date` DATE,
);
INSERT INTO table1
(`cycle`, `date`)
VALUES
('1', '15-Jan-21'),
('2', '01-Aug-21'),
('3', '08-sep-21'),
('4', '15-Dec-21');
Output :
If I understand correctly, you might want to use LEAD window function with DATE_SUB if your MySQL version supports that.
SELECT *
FROM (
SELECT *,DATE_SUB(LEAD(`date`) OVER(ORDER BY cycle), INTERVAL 1 DAY) endDate
FROM table1
) t1
WHERE endDate IS NOT NULL
sqlfiddle
I have a table that stores the records for users' different sessions(subscribe, unsubscribe, away, online). I am able to calculate the time duration for each session using the following given query.
There is a scenario that supposes a user starts his online session on "15-May-2022 at 11:00:00 PM", after that on the next day he set himself away on "16-May-2022 at 02:00:00 AM"
Total online is 3 Hours which I am getting as the last row on the date 15-May-2022.
But I need like this
On 15-May till "15-May-2022 23:59:59" it was online for 1 Hour and on 16-May from "16-May-2022 00:00:00 to 16-May-2022 at 02:00:00 AM", it was online for 2 Hours. So in response, it should return 1 hour for 15-May and 2 hours for 16-May, not a total of 3 hours on 15-May.
I am using the lead function to get the duration from the created_at column, is there any way in which I can restrict the lead function to calculate duration till the next created_at till 23:59:59.
Here is my working query. I am using the latest MySQL(8) version.
select `id`, `user_id`, `status`, `created_at`,
SEC_TO_TIME(TIMESTAMPDIFF(SECOND, created_at,
LEAD(created_at) OVER (PARTITION BY user_id ORDER BY created_at))) as duration,
date(created_at) as date from `user_websocket_events` as `all_status`
where created_at between '2022-05-15 00:00:00' and '2022-05-16 23:59:59' and `status` is not null
and user_id in (69) order by `id` asc;
Here is some sample data.
INSERT INTO user_websocket_events (id, user_id, event, status, extra_attributes, created_at, updated_at) VALUES (10816, 69, 'subscribe', 'online', null, '2022-05-15 12:57:31', '2022-05-14 10:57:37');
INSERT INTO user_websocket_events (id, user_id, event, status, extra_attributes, created_at, updated_at) VALUES (10817, 69, 'away', 'away', null, '2022-05-15 20:57:31', '2022-05-14 10:57:37');
INSERT INTO user_websocket_events (id, user_id, event, status, extra_attributes, created_at, updated_at) VALUES (10818, 69, 'online', 'online', null, '2022-05-15 22:57:31', '2022-05-14 10:57:37');
INSERT INTO user_websocket_events (id, user_id, event, status, extra_attributes, created_at, updated_at) VALUES (10819, 69, 'away', 'away', null, '2022-05-16 02:57:31', '2022-05-14 10:57:37');
INSERT INTO user_websocket_events (id, user_id, event, status, extra_attributes, created_at, updated_at) VALUES (10820, 69, 'unsubscribe', 'unsubscribe', null, '2022-05-16 03:57:31', '2022-05-14 10:57:37');
Using an on-the-fly calendar table to split a session by days
with recursive calendar as (
select timestamp('2022-05-01 00:00') start_time, timestamp('2022-05-01 23:59:59') end_time, 1 id
union all
select start_time + interval 1 day, end_time + interval 1 day, id+1
from calendar
where id < 100
)
select e.id, e.status, date(greatest(c.start_time, e.created_at)) date,
greatest(c.start_time, e.created_at) as created_at,
least(c.end_time, e.ended_at) as ended_at
from (
select `id`, `user_id`, `status`, `created_at`,
-- a session end is restricted to the end of the requierd interval
LEAD(created_at, 1, '2022-05-16 23:59:59') OVER (PARTITION BY user_id ORDER BY created_at) as ended_at
from `user_websocket_events`
where
-- only sessions started within the requierd interval
created_at between '2022-05-15 00:00:00' and '2022-05-16 23:59:59' and `status` is not null
and user_id in (69)
) e
join calendar c on c.start_time < e.ended_at and e.created_at < c.end_time
order by id;
db<>fiddle
You need to handle it using CASE statement.
Now instead of the actual created_at and LEAD(created_at), we need something like below.
First Case:
If the created_at and LEAD(created_at) falls on different date, then consider date(created_at) + '23:59:59' else consider created_at as ENDTIME.
CASE
WHEN Date(lead_created_at)=Date(created_at) THEN lead_created_at
ELSE Addtime(Timestamp(Date(created_at)),'23:59:59')
END
Second Case:
If the created_at and LAG(created_at) falls on different date, then consider date(created_at) + '00:00:00' else consider created_at as STARTTIME.
CASE
WHEN Date(lag_created_at)=Date(created_at) THEN created_at
ELSE Timestamp(Date(created_at))
END
Finally, the query can be written as below to get the desired output.
SELECT `id`,
`user_id`,
`status`,
`created_at`,
CASE
WHEN Date(lag_created_at)=Date(created_at) THEN created_at
ELSE Timestamp(Date(created_at))
end new_starttime,
CASE
WHEN Date(lead_created_at)=Date(created_at) THEN lead_created_at
WHEN lead_created_at is null then null
ELSE Addtime(Timestamp(Date(created_at)),'23:59:59')
end AS new_endtime,
Sec_to_time(Timestampdiff(second,
CASE
WHEN Date(lag_created_at)=Date(created_at) THEN created_at
ELSE Timestamp(Date(created_at))
end,
CASE
WHEN Date(lead_created_at)=Date(created_at) THEN lead_created_at
WHEN lead_created_at is null then null
ELSE Addtime(Timestamp(Date(created_at)),'23:59:59')
end )) AS duration,
date
FROM (
SELECT `id`,
`user_id`,
`status`,
`created_at`,
(Lead(created_at) over (partition BY user_id ORDER BY created_at)) AS lead_created_at,
coalesce(lag(created_at) over (partition BY user_id ORDER BY created_at),created_at) AS lag_created_at,
date(created_at) AS date
FROM `user_websocket_events` AS `all_status`
WHERE created_at BETWEEN '2022-05-15 00:00:00' AND '2022-05-16 23:59:59'
AND `status` IS NOT NULL
AND user_id IN (69) )tmp
ORDER BY `id` ASC;
Resultset:
id
user_id
status
created_at
new_starttime
new_endtime
duration
date
10816
69
online
2022-05-15 12:57:31
2022-05-15 12:57:31
2022-05-15 20:57:31
08:00:00
2022-05-15
10817
69
away
2022-05-15 20:57:31
2022-05-15 20:57:31
2022-05-15 22:57:31
02:00:00
2022-05-15
10818
69
online
2022-05-15 22:57:31
2022-05-15 22:57:31
2022-05-15 23:59:59
01:02:28
2022-05-15
10819
69
away
2022-05-16 02:57:31
2022-05-16 00:00:00
2022-05-16 03:57:31
03:57:31
2022-05-16
10820
69
unsubscribe
2022-05-16 03:57:31
2022-05-16 03:57:31
null
null
2022-05-16
Note: The query will not handle the scenario where sessions last more than 48 hour.
DB Fiddle: Try it here
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
I have a table containing alternating ON & OFF events with its timestamp. How do i calculate total time between each ON & OFF?
Status Timestamp
============================
ON 2019-01-01 07:00:00
OFF 2019-01-01 08:30:00
ON 2019-01-01 09:00:00
OFF 2019-01-01 10:00:00
ON 2019-01-01 10:30:00
OFF 2019-01-01 11:30:00
Consider the following...
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
dt DATETIME NOT NULL,
status VARCHAR(5) NOT NULL
);
INSERT INTO my_table VALUES
(1,'2015-01-01 13:00:00','ON'),
(2,'2015-01-01 13:10:00','OFF'),
(3,'2015-01-01 13:20:00','ON'),
(4,'2015-01-01 13:30:00','OFF'),
(5,'2015-01-01 13:35:00','ON'),
(6,'2015-01-01 13:40:00','OFF'),
(7,'2015-01-01 13:50:00','ON'),
(8,'2015-01-01 15:00:00','OFF');
SELECT x.*,
TIMEDIFF(MIN(y.dt),x.dt) AS TimeDiff
FROM my_table AS x
INNER JOIN my_table AS y ON y.dt >= x.dt
WHERE x.status = 'ON' AND y.status = 'OFF'
GROUP
BY x.id;
Refer DB FIDDLE For More:
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=00dc040da540f852f08b2f02750bc16d
CREATE TABLE events (
`status` VARCHAR(3),
`timestamp` VARCHAR(19)
);
INSERT INTO events
(`status`, `timestamp`)
VALUES
('ON', '2019-01-01 07:00:00'),
('OFF', '2019-01-01 08:30:00'),
('ON', '2019-01-01 09:00:00'),
('OFF', '2019-01-01 10:00:00'),
('ON', '2019-01-01 10:30:00'),
('OFF', '2019-01-01 11:30:00');
SELECT
TIME_FORMAT(SEC_TO_TIME(TIME_TO_SEC(
SUM(TIMEDIFF(offtime, ontime))
)), '%H:%i')
AS total FROM (
SELECT e.timestamp AS offtime, (SELECT timestamp
FROM events AS st WHERE st.timestamp < e.timestamp AND st.status = "ON"
ORDER BY st.timestamp DESC LIMIT 1) AS ontime
FROM events AS e WHERE e.status='OFF') AS onoffs
Selects every OFF record, joins the most recent ON record to it, sums time ranges. With your data it gives the result: total 03:30
Doesn't account for open ranges. E.g. if the data series is started with OFF; or if it ends with ON, the time up to current moment would not be counted.
https://www.db-fiddle.com/f/hr27GhACxGd7ZvFaa52xiK/0#
I have products table in which I have all the products that are being sold or ready to sell.
Here is table schema
CREATE TABLE `products` (
`Product_Name` varchar(255) DEFAULT NULL,
`Product_Status` int(11) DEFAULT NULL,
`Sell_date` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;
Every time a product is being sold its status becomes 1.
I am trying to get all the products sold on yesterday.How would I do that in sql query.
Select Product_Name from products where status = 1 and Sell_date = ??
My questions is how to go back A whole day or N number of days in timestamp.
For products sold in the $N last days :
SELECT
Product_Name
FROM products
WHERE status = 1
AND TIMESTAMPDIFF(DAY, `Sell_date`, NOW()) <= $N
SELECT Product_Name
FROM products WHERE status = 1 and Sell_date = DATE_SUB( Sell_date, INTERVAL 1 DAY )
DATE_SUB function is used for substract preticular time interval from the given date i think this will helpful to you.