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.
Related
I have a table with column named started_at
I want to get statistics of new inserted row by last day , week , one month and three month .
the started_at column format is default MySQL timestamp which is string .
before posting this question , I try this querys
SELECT WEEK(`started_at`) , COUNT(*) AS nbr FROM users_in_bots WHERE `bot_id` = 5529 GROUP BY WEEK (`started_at`);
SELECT MONTH(`started_at`), COUNT(*) AS nbr FROM users_in_bots WHERE `bot_id` = 5529 GROUP BY MONTH(`started_at`);
and the result is not what I want .
I want get all statistics with just one query .
the table structure :
CREATE TABLE `users_in_bots` (
`user_id` bigint(20) NOT NULL,
`bot_id` bigint(20) NOT NULL,
`started_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
sample row :
INSERT INTO `users_in_bots` (`user_id`, `bot_id`, `started_at`) VALUES
(2314, 509492849, '2022-02-27 03:59:21'),
(28779, 210686266, '2022-03-03 21:51:38'),
(28779, 503513058, '2022-04-01 12:28:37'),
(28779, 515774720, '2022-03-25 08:25:16'),
(28779, 518099352, '2022-03-22 17:22:38'),
(28779, 519646468, '2022-03-04 22:02:02'),
(84588, 517141146, '2022-03-28 12:36:45'),
(87075, 509498849, '2022-02-27 03:59:21'),
(116264, 210509102, '2022-02-27 00:02:54'),
(116264, 212268136, '2022-02-27 00:29:06');
expected output ( what i wish to use in my application ):
new users in last 24 hour : 42
new users in last week : 532
new users in last month : 4568
and same with 3 and six month and all the time .
You can use conditional aggregation to get the results you want. For example:
SELECT SUM(started_at BETWEEN NOW() - INTERVAL 1 HOUR AND NOW()) last_hour,
SUM(started_at BETWEEN CURDATE() - INTERVAL 1 WEEK AND CURDATE()) last_week,
SUM(started_at BETWEEN CURDATE() - INTERVAL 1 MONTH AND CURDATE()) last_month,
SUM(started_at BETWEEN CURDATE() - INTERVAL 3 MONTH AND CURDATE()) last_3month,
SUM(started_at BETWEEN CURDATE() - INTERVAL 6 MONTH AND CURDATE()) last_6month
FROM users_in_bots
Output (for your sample data as of 2022-04-13):
last_hour last_week last_month last_3month last_6month
0 0 4 10 10
Demo on dbfiddle
I have a table structure:
CREATE TABLE `tv_series_intervals` (
`id_tv_series` int(11) NOT NULL,
`week_day` smallint(1) NOT NULL DEFAULT 1,
`show_time` TIMESTAMP NOT NULL)
week day in a format 1,2,3,4,5,6,7
show_time it's a converted time to timestamp, for example, 11-45 will convert to 1970-01-01 11:45:00
How can I get next id_tv_series depending on today's datetime?
Does anyone have an idea by what query can I do that?
One example:
TV show (with 1 ID) shows on Wednesday at 00:00 and today is Tuesday 23:59, it should return ID 1
can you change structure to
CREATE TABLE tv_series_intervals (
id_tv_series int(11) NOT NULL,
week_day smallint(1) NOT NULL DEFAULT 1,
show_time TIME NOT NULL)
or perhaps you can include the function to get time sorted by
select *,from_unixtime(show_time, '%h:%i:%s') time from tv_series_interval
order by time
You can use this query to achieve your goal.
Assume today is day 1 and the time is 1970-01-01 12:45:00.
(SELECT * from db WHERE show_time > '1970-01-01 12:45:00' AND week_day = 1
ORDER BY show_time LIMIT 1)
UNION ALL
(SELECT * from db WHERE week_day > 1 AND NOT EXISTS
(SELECT * from db WHERE show_time > '1970-01-01 12:45:00' and week_day = 1 ORDER BY show_time LIMIT 1)
ORDER BY week_day , show_time LIMIT 1)
UNION ALL
(SELECT * from db WHERE week_day < 1 and NOT EXISTS
(SELECT * from db WHERE show_time > '1970-01-01 12:45:00' AND week_day = 1 ORDER BY show_time LIMIT 1) AND NOT EXISTS
(SELECT * from db WHERE week_day > 1)
ORDER BY week_day , show_time LIMIT 1)
We check if we have the next id today if there wasn't any id today we check for the nearest id on other days.
In the third select we check if today is 7 and we have to roll back to 1 and check for the nearest id on day 1.
You can use float type instead of timestamp for column show_time that makes sense as well.
If I was you and could modify the backend. I store the next timestamp totally in the database it could reduce the complexity. (e.g. next tv show will be on 18-02-2022 12:10:00)
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;
I'm looking for a MySql query who returns last 6 months ago update data OR/AND, if the sum of results is less than 100, the next n rows to complete to 100.
The table create query :
CREATE TABLE `content` (
`id` int(11) NOT NULL,
`id_cat` int(11) NOT NULL,
`title` text,
`lastUpdate` date NOT NULL,
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
ALTER TABLE `content`
ADD PRIMARY KEY (`id`);
ALTER TABLE `content`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=10175;
The first part of the query is :
SELECT *
FROM content,
categories
WHERE categories.id = content.id_cat
AND lastUpdate > DATE_SUB(now(), INTERVAL 6 MONTH)
ORDER BY lastUpdate DESC,
content.id DESC,
content.title ASC
I don't find explanations to do this. Someone could help me ?
As I understand the question, you want all of the records within the last 6 months; if that set has fewer than 100 records, then select the top 100 most recent records.
One approach is as follows:
SELECT *
FROM content
INNER JOIN categories
ON categories.id = content.id_cat
WHERE lastUpdate > DATE_SUB(now(), INTERVAL 6 MONTH)
OR content.id IN (SELECT content.id FROM content
INNER JOIN categories
ON categories.id = content.id_cat
ORDER BY lastUpdate DESC,
content.id DESC,
content.title ASC
LIMIT 100)
ORDER BY lastUpdate DESC,
content.id DESC,
content.title ASC
Background / Application
I have a MySQL database containing a table of rentable properties and a table of bookings for these properties. There is also a search feature for finding available properties between two provided dates. When searching, the user can enter the start date, the amount of days they wish to stay, and a date flexibility of up to +/- 7 days. A booking can start on the same day as another booking ends (party 1 leaves in the morning, party 2 arrives in the evening).
I am having difficulty implementing the flexibility feature efficiently.
Schema
CREATE TABLE IF NOT EXISTS `property` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `property_booking` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`property_id` bigint(20) DEFAULT NULL,
`name` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL,
`date_start` date DEFAULT NULL,
`date_end` date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Sample Data
INSERT INTO `property` (`name`)
VALUES ('Property 1'), ('Property 2'), ('Property 3');
INSERT INTO `property_booking` (`property_id`,`name`,`date_start`,`date_end`)
VALUES (1, 'Steve', '2011-03-01', '2011-03-08'),
(2, 'Bob', '2011-03-13', '2011-03-20'),
(3, 'Jim', '2011-03-16', '2011-03-23');
Sample Scenario
The user selects that they want to start their stay on 2011-03-10, they want to stay for 7 days, and they have a flexibility of +/- 2 days. I have compiled an image that visualises the data and parameters below. (Red: Booking 1, Green: Booking 2, Stripes: Booking 3, Blue: Date range (2011-03-10, + 7 days and +/- 2 days flexibility))
Expected Result
Property 1 (Bookings available throughout date range)
Property 3 (Bookings available starting on 2011-03-08 or 2011-03-09)
Current Method
My current query checks for overlap for all 7 day date ranges within the total searchable date range, like this:
SELECT p.`id`, p.`name`
FROM `property` p
WHERE (NOT (EXISTS (SELECT p2.`name` FROM `property_booking` p2 WHERE (p2.`property_id` = p.`id` AND '2011-03-10' < DATE_SUB(p2.`date_end`, INTERVAL 1 DAY) AND '2011-03-17' > DATE_ADD(p2.`date_start`, INTERVAL 1 DAY)))))
OR (NOT (EXISTS (SELECT p3.`name` FROM `property_booking` p3 WHERE (p3.`property_id` = p.`id` AND '2011-03-11' < DATE_SUB(p3.`date_end`, INTERVAL 1 DAY) AND '2011-03-18' > DATE_ADD(p3.`date_start`, INTERVAL 1 DAY)))))
OR (NOT (EXISTS (SELECT p4.`name` FROM `property_booking` p4 WHERE (p4.`property_id` = p.`id` AND '2011-03-09' < DATE_SUB(p4.`date_end`, INTERVAL 1 DAY) AND '2011-03-16' > DATE_ADD(p4.`date_start`, INTERVAL 1 DAY)))))
OR (NOT (EXISTS (SELECT p5.`name` FROM `property_booking` p5 WHERE (p5.`property_id` = p.`id` AND '2011-03-12' < DATE_SUB(p5.`date_end`, INTERVAL 1 DAY) AND '2011-03-19' > DATE_ADD(p5.`date_start`, INTERVAL 1 DAY)))))
OR (NOT (EXISTS (SELECT p6.`name` FROM `property_booking` p6 WHERE (p6.`property_id` = p.`id` AND '2011-03-08' < DATE_SUB(p6.`date_end`, INTERVAL 1 DAY) AND '2011-03-15' > DATE_ADD(p6.`date_start`, INTERVAL 1 DAY)))));
On the sample dataset, it's reasonably quick, but on much larger datasets it's going to get pretty sluggish, even more so when you build the full +/- 7 day flexibility.
Does anyone have any suggestions as to how this query could be better written?
Ok, here's a tricky answer for a tricky question...
SELECT * FROM property AS p
LEFT JOIN
(
SELECT property_id, DATEDIFF(MAX(date_end),20110308) AS startblock,
DATEDIFF(20110319,MIN(date_start))-1 AS endblock
FROM property_booking AS pb
WHERE date_start < 20110319 || date_end >= 20110308
GROUP BY property_id
HAVING LEAST(startblock,endblock) > 4
) AS p2 ON p.id = p2.property_id
WHERE p2.property_id IS NULL;
The subquery selects all the properties that are not eligible. The LEFT JOIN with IS NULL basically works out the exclusion (negation on the ineligible properties)
20110308 is the desired start date -2 days ( because +/-2 day flexibility)
20110319 is the desired end date +2 days
The number 4 in the HAVING LEAST(startblock,endblock) > 4 in twice your +/- number (2*2)
It took me a while to work it out (but your question was interesting and I had time on my hand)
I've tested it with edge cases and it worked for all the test cases I've thrown at it...). The logic behind it is a bit odd but a good old pen and paper helped me work it out!
Edit
Unfortunately I realized that this will work for most cases but not all... (2 single day bookings at the very beginning and end of the lookup period makes a property unavailable even though it should be available).
The problem here is that you have to look up information that's not 'present' in the DB and reconstruct it from what data you have. Check out my comment on your question to see a better way to deal with the problem
I think this is what you're looking for:
SELECT MAX( IF( ( b.date_start < '2011-03-08' + INTERVAL 7 DAY
AND b.date_end > '2011-03-08'), 1, 0)) AS is_booked,
p.id,
p.name
FROM property p
LEFT JOIN property_booking b ON p.id = b.property_id
GROUP BY p.id
HAVING is_booked < 1
If you want to include the leeway, expand the MAX() aggregate to include the options:
SELECT MAX( IF( ( b.date_start < '2011-03-08' + INTERVAL 7 DAY
AND b.date_end > '2011-03-08')
AND ( b.date_start < '2011-03-08' + INTERVAL 7 DAY + INTERVAL 1 DAY
AND b.date_end > '2011-03-08' + INTERVAL 1 DAY)
AND ( b.date_start < '2011-03-08' + INTERVAL 7 DAY + INTERVAL 2 DAY
AND b.date_end > '2011-03-08' + INTERVAL 2 DAY), 1, 0)
) AS is_booked,
p.id,
p.name
FROM property p
LEFT JOIN property_booking b ON p.id = b.property_id
GROUP BY p.id
HAVING is_booked < 1
If I'm understanding your question right, this GROUP BY query should cover it more efficiently than multiple subqueries.