We had a MySQL query that selected records and was required to also show Sold records for 60days before being removed from the shown results.
Logic was such that after changing a record from some invStatus to 1 which equals sold, we would filter it from our records after 60 days.
The problem is that if the filter is applied in a single query even active records are getting dropped if they are not updated within that 60 day window.
So how to select all records and then only filter a subset of those records based on date interval?
Should I select ALL the Ids and then filter those that are status sold and then apply the date interval in a subquery or run two queries and concatenate the two?
UPDATE:
SQLFiddle created that shows (10) records.
The goal is to not lose any invStatus = 0 but filter invStatus records that = 1 by NOT returning them if Update_date is older than 60 days from today
There are (7) records that have a invStatus = 0 (not Sold)
and (3) records that have invStatus = 1 (Sold)
SELECT
tblinventory.invId,
tblinventory.`Update_date`,
tblinventory.invStatus
FROM
tblinventory
WHERE NOT (Update_date < NOW() - INTERVAL 60 DAY)
ORDER BYtblinventory.invId
results in (6) records
5 which are invStatus = 0
1 that is invStatus = 1
Should be
(7) invStatus 0’s as they ALL should be present
(1) invStatus = 1 that is within 60 days
SQLFiddle schema:
CREATE TABLE IF NOT EXISTS `tblinventory` (
`invId` int(4) NOT NULL,
`Update_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`invStatus` int(3) NOT NULL DEFAULT '0'
) DEFAULT CHARSET=utf8;
INSERT INTO `tblinventory` (`invId`,`Update_date`,`invStatus`)
VALUES
("3777","2019-08-06 00:00:00","1"),
("3782","2019-08-30 00:00:00","0"),
("3820","2019-04-04 00:00:00","0"),
("3821","2019-03-21 00:00:00","1"),
("3835","2019-02-20 00:00:00","0"),
("3836","2019-06-30 00:00:00","1"),
("4035","2019-08-25 00:00:00","0"),
("4036","2019-09-01 00:00:00","0"),
("4037","2019-09-01 00:00:00","0"),
("4038","2019-09-01 00:00:00","0");
Query:
SELECT
tblinventory.invId,
tblinventory.`Update_date`,
tblinventory.invStatus
FROM
tblinventory
WHERE NOT (Update_date < NOW() - INTERVAL 60 DAY) AND invStatus = 1
ORDER BY
tblinventory.invId
Comparative Query:
WHERE NOT (Update_date < NOW() - INTERVAL 60 DAY)
https://www.db-fiddle.com/f/3KuYDHgYaNtaB8mMuatrz2/0
I guess you need a simple UNION ALL clause. Presumably invStatus <> 1 means non sold entities, You can try below query -
SELECT
tblinventory.invId,
tblinventory.`Update_date`,
tblinventory.invStatus
FROM
tblinventory
WHERE `invStatus` = 0 OR (Update_date >= NOW() - INTERVAL 60 DAY)
ORDER BY
tblinventory.invId
Related
Consider I have the following table and current date is 2022-09-01:
Requirement: I want to get all users that have no event_name like cbt care in the past 14 days and onwards into the future.
I have this query:
SELECT * FROM test_table
WHERE event_name LIKE "%cbt care%"
AND start_date <= DATE_SUB(NOW(), INTERVAL 14 DAY)
;
Which returns:
The issue is that user_id = x does have a cbt care event in 2022-09-10 which is 9 days ahead of current date (2022-09-01).
How to return only users satisfy requirement posted above?
SELECT user_id,
COUNT(CASE WHEN event_name LIKE '%cbt care%' AND start_date
> CURDATE() - INTERVAL 14 day THEN 1 END) AS count_recent
FROM test_table
GROUP BY user_id
HAVING count_recent = 0;
https://www.db-fiddle.com/f/64j7L1VZsVdLYqmcQ2NrvV/0
The CASE expression returns 1 for each row with the conditions you described (a specific event name and a start date after the date 14 days ago, which includes all of the future dates too). For rows that don't match that condition, the CASE returns NULL. There's an implicit ELSE NULL in any CASE expression.
COUNT(<expr>), like many set functions, ignores NULLs. It will only count the occurrences of non-NULL values. So if the count returns 0, then the CASE returned only NULLs, which means there are no recent or future 'cbt care' events for that user.
select id
,user_id
,event_name
,start_date
from (
select *
,count(case when abs(datediff(curdate(),start_date)) <= 14 and event_name like "%cbt care%" then 1 end) over (partition by user_id) as cw
from t
) t
where cw = 0
id
user_id
event_name
start_date
0
a
cbt care
2022-06-01 20:00:00
Fiddle
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'm having some difficulties on applying certain conditions if a column is empty or not.
My table is as follows:
CREATE TABLE `meets` (
`id` INT,
`scheduled` VARCHAR(255),
`status` INT
);
INSERT INTO meets(id,scheduled,status) VALUES (1,'','1');
INSERT INTO meets(id,scheduled,status) VALUES (2,'','2');
INSERT INTO meets(id,scheduled,status) VALUES (2,'1613220631','3'); // in 30 minutes
INSERT INTO meets(id,scheduled,status) VALUES (2,'1644756631','3'); // 2022
What I did so far is next:
SELECT * FROM meets WHERE FROM_UNIXTIME(scheduled) BETWEEN DATE_SUB(NOW(), INTERVAL 30 MINUTE) AND DATE_SUB(NOW(), INTERVAL -30 MINUTE) ORDER BY `id` DESC
The above only selects the record that has a timestamp in the following/past 30 minutes.
Other than that record, I also need to select record id 1 because it has status == 1.
So basically
if scheduled column is empty, check for status to be 1 and select if true;
if scheduled column is timestamp, apply condition from the query posted above;
Any ideas? Thank you!
You could add the missing rows using union
SELECT *
FROM meets
WHERE FROM_UNIXTIME(scheduled)
BETWEEN DATE_SUB(NOW(), INTERVAL 30 MINUTE) AND DATE_SUB(NOW(), INTERVAL -30 MINUTE)
ORDER BY `id` DESC
UNION
select * from meets where scheduled = '' AND status = 1
We have multiple invStatus values (1-10) and want to exclude only one status type (1) BUT only those of that type that are a older than X number of days. So all records will show but NOT those who's invStatus = 1 and is older than X days. invStatus = 1 and younger than X days will be included in the recordset.
Do I select all records generically, then in a subquery filter those of status = 1 that are older than X days?
The query below uses NOT IN in an attempt to select those records to exclude but it is not working and also seems to be inefficient as it takes a couple seconds to execute.
SELECT
tblinventory.invId,
tblinventory.invTitle,
tblinventory.invStatus,
tblhouseinfo.Address,
tblhouseinfo.City,
tblhouseinfo.`State`,
tblhouseinfo.Zip,
tblhouseinfo.Update_date,
CURRENT_DATE() - INTERVAL 10 DAY AS dateEx
FROM
tblinventory
LEFT OUTER JOIN tblhouseinfo ON tblinventory.invId = tblhouseinfo.addInfoID
WHERE
invReleased = 0
AND invStatus NOT IN (SELECT invId from tblhouseinfo WHERE invStatus = 1
AND tblhouseinfo.Update_date < CURRENT_DATE() - INTERVAL 10 DAY )
ORDER BY
`tblhouseinfo`.`Update_date` DESC
I could filter the results with PHP on the page level but this also seems less than efficient and would prefer to perform this task using the best practices.
UPDATE:
There are a total of 155 rows.
All tblhouseinfo.Update_date (timestamp) values are "2017-09-06 10:53:17" (Aug 9th) accept three I changed for testing to "2017-07-06 10:53:17
" (July 6th)
Utilizing the suggestion for :
AND NOT (invStatus = 1 AND tblhouseinfo.Update_date > CURRENT_DATE() - INTERVAL 10 DAY )
60 records are excluded not the expected 3.
"2017-08-28" is the current result from CURRENT_DATE() - INTERVAL 10 DAY which should be within the 10 day range to select "2017-09-06 10:53:17" and only exclude the three records that are "2017-07-06 10:53:17"
FINAL WORKING SOLUTION/Query:
SELECT
tblinventory.invId,
tblinventory.invTitle,
tblinventory.invStatus,
tblhouseinfo.Address,
tblhouseinfo.City,
tblhouseinfo.`State`,
tblhouseinfo.Zip,
tblhouseinfo.Update_date,
CURRENT_DATE() - INTERVAL 10 DAY AS dateEx
FROM
tblinventory
LEFT OUTER JOIN tblhouseinfo ON tblinventory.invId = tblhouseinfo.addInfoID
WHERE
invReleased = 0
AND NOT (invStatus = 1 AND tblhouseinfo.Update_date < CURRENT_DATE() - INTERVAL 10 DAY )
ORDER BY
`tblhouseinfo`.`Update_date` DESC
SELECT
tblinventory.invId,
tblinventory.invTitle,
tblinventory.invStatus,
tblhouseinfo.Address,
tblhouseinfo.City,
tblhouseinfo.`State`,
tblhouseinfo.Zip,
tblhouseinfo.Update_date,
CURRENT_DATE() - INTERVAL 10 DAY AS dateEx
FROM
tblinventory
LEFT OUTER JOIN tblhouseinfo ON tblinventory.invId = tblhouseinfo.addInfoID
WHERE
invReleased = 0
AND NOT (invStatus = 1 AND tblhouseinfo.Update_date < CURRENT_DATE() - INTERVAL 10 DAY )
ORDER BY
`tblhouseinfo`.`Update_date` DESC
You don't need to select invID from the other table if you know you never want the ID #1 (invStatus 1). But you can also throw in an AND statement for the # of days.
I always use timestamps (in UNIX) for recording data entry / modification.
AND (timestamp >= beginTimestamp AND timeStamp <= endTimestamp)
I have this query i use to get statistics of blogs in our own tracking system.
I use union select over 2 tables as we daily aggregate data in 1 table and keeps todays data in another table.
I want to have the last 10 months of traffic show.. This query does that, but of there is no traffic in a specific month that row is not in the result.
I have previously used a calendar table in mysql to join against to at avoid that, but im simply not skilled enoght to rewrite this query to join against that calendar table.
The calendart table has 1 field called "datefield" which i date format YYY-MM-DD
This is the current query i use
SELECT FORMAT(SUM(`count`),0) as `count`, DATE(`date`) as `date`
FROM
(
SELECT count(distinct(uniq_id)) as `count`, `timestamp` as `date`
FROM tracking
WHERE `timestamp` > now() - INTERVAL 1 DAY AND target_bid = 92
group by `datestamp`
UNION ALL
select sum(`count`),`datestamp` as `date`
from aggregate_visits
where `datestamp` > now() - interval 10 month
and target_bid = 92
group by `datestamp`
) a
GROUP BY MONTH(date)
Something like this?
select sum(COALESCE(t.`count`,0)),s.date as `date`
from DateTable s
LEFT JOIN (SELECT * FROM aggregate_visits
where `datestamp` > now() - interval 10 month
and target_bid = 92) t
ON(s.date = t.datestamp)
group by s.date