SQL query get rows after and before number of days - mysql

I'm inheriting an SQL query that gets data from my database table based on the number of days before the current date, I'd like to extend this functionality to also include data after the current date, I've tried extending it by adding a new line but my SQL query doesn't return any data, here's the current query:
SELECT
IF((
SELECT
send.id AS "true"
FROM
sends send
WHERE
send.sent = 0 AND
send.subscription_id = subscription.id
LIMIT 1
), true, false) AS already_queued
FROM
subscriptions subscription
WHERE
subscription.unsubscribed = 0 AND
subscription.source_id = 12 AND
DATE(subscription.date_added) <= (CURRENT_DATE - INTERVAL 1 DAY)
ORDER BY
subscription.date_added
DESC
Right now it's the following line that handles the data after a number of days:
DATE(subscription.date_added) <= (CURRENT_DATE - INTERVAL 1 DAY)
Where 1 is replaced dynamically with the value, I now want to add a new line:
DATE(subscription.date_added) >= (CURRENT_DATE - INTERVAL 7 DAY)
So this should return data between the two dates but doesn't, what am I missing from the combined query to make it work:
SELECT
IF((
SELECT
send.id AS "true"
FROM
sends send
WHERE
send.sent = 0 AND
send.subscription_id = subscription.id
LIMIT 1
), true, false) AS already_queued
FROM
subscriptions subscription
WHERE
subscription.unsubscribed = 0 AND
subscription.source_id = 12 AND
DATE(subscription.date_added) >= (CURRENT_DATE - INTERVAL 7 DAY) AND
DATE(subscription.date_added) <= (CURRENT_DATE - INTERVAL 1 DAY)
ORDER BY
subscription.date_added
DESC

Related

Aliases in MySQL and do maths

I need to workout the effectiveness of a user to display in a report, i complied the following statement
SELECT COUNT(`call_id`) AS logged
FROM `tbl_calls`
WHERE `user_id_attended_by` = 24
AND YEAR(`date_ack_by_tech`) = YEAR(CURRENT_DATE - INTERVAL 1 YEAR)
AND MONTH(`date_ack_by_tech`) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)
AND `fk_supplier_id` = 3
UNION ALL
SELECT COUNT(call_id) AS ACK
FROM `tbl_calls`
WHERE YEAR(`date_logged`) = YEAR(CURRENT_DATE - INTERVAL 1 YEAR)
AND MONTH(`date_logged`) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)
AND `repaired_by` = 24
AND `fk_supplier_id` = 3
The output for the above motioned statement as follows,
I need to get the percentages of the two totals in the pictures to add it to a report to get the users performance, I tried to create a temp table and entering the data into it but could not get it working in xampp.
SELECT logged,
100*logged/(logged+ack) percent_logged,
ack,
100*ack/(logged+ack) percent_ack
FROM (
SELECT SUM(`user_id_attended_by` = 24) AS logged,
SUM(repaired_by` = 24) AS ack
FROM `tbl_calls`
WHERE YEAR(`date_ack_by_tech`) = YEAR(CURRENT_DATE - INTERVAL 1 YEAR)
AND MONTH(`date_ack_by_tech`) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)
AND `fk_supplier_id` = 3
) subquery
?

Counting all rows in column with two different date conditions

I'm trying to turn two count queries with date conditions (the ones below) into one query.
SELECT COUNT(*) as yesterday FROM orders WHERE DATE(timedate) = DATE(NOW() - INTERVAL 1 DAY)
SELECT COUNT(*) as yesterday FROM orders WHERE DATE(timedate) = DATE(NOW() - INTERVAL 2 DAY)
Following the advice of another answer I created the following, but that doesn't seem to work syntax-wise, and I'm not quite sure why. Is there another way to do this? I can't find a similar question on this
SELECT
SUM(IF(DATE(timedate) = DATE(NOW() - INTERVAL 1 DAY))) AS testcount1,
SUM(IF(DATE(timedate) = DATE(NOW() - INTERVAL 2 DAY))) AS testcount2
FROM
orders
You're missing the output values for the IF expression. Also you should use CURRENT_DATE() so you don't need to convert to a DATE:
SELECT
SUM(IF(DATE(timedate) = CURRENT_DATE() - INTERVAL 1 DAY, 1, 0)) AS testcount1,
SUM(IF(DATE(timedate) = CURRENT_DATE() - INTERVAL 2 DAY, 1, 0)) AS testcount2
FROM
orders
Note that MySQL treats boolean expressions as 1 (true) or 0 (false) in a numeric context, so you can actually SUM the expression without needing the IF:
SELECT
SUM(DATE(timedate) = CURRENT_DATE() - INTERVAL 1 DAY) AS testcount1,
SUM(DATE(timedate) = CURRENT_DATE() - INTERVAL 2 DAY) AS testcount2
FROM
orders
You want conditional aggregation. I would phrase the query as follows:
SELECT
SUM(
timedate >= CURRENT_DATE - INTERVAL 1 DAY
and timedate < CURRENT_DATE
) AS testcount1,
SUM(
timedate >= CURRENT_DATE - INTERVAL 2 DAY
and timedate < CURRENT_DATE- INTERVAL 1 DAT
) AS testcount2
FROM orders
Details:
this uses a nice feature of MySQL, that evaluates false/true conditions as 0/1 in numeric context
no date functions are applied on the timedate column : instead, we do litteral date comparisons. This is much more efficient, since the database can possibly take advantage of an index on the datetime column
You might also want to add a WHERE clause to the query:
WHERE
timedate >= CURRENT_DATE - INTERVAL 2 day
AND timedate< CURRENT_DATE

How to select records but exclude if one type is outside a subquery?

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)

How do I subtract two results from a SELECT statement within that statement?

This pulls back two int values of yesterday and today. I'd like to subtract the two results from within the statement in a third column called difference:
SELECT (
SELECT COUNT(*)
FROM collectors_users
WHERE DATE(dateadded) = CURDATE() - INTERVAL 1 DAY
) AS yesterday, COUNT(*) AS today
FROM collectors_users
WHERE DATE(dateadded) = CURDATE()
You need to repeat the expressions. SQL (in general) does not allow you to re-use column aliases in the same SELECT. You can simplify the logic to:
SELECT SUM(DATE(dateadded) = CURDATE() - INTERVAL 1 DAY) AS yesterday,
SUM(DATE(dateadded) = CURDATE()) as today,
(SUM(DATE(dateadded) = CURDATE()) -
SUM(DATE(dateadded) = CURDATE() - INTERVAL 1 DAY)
) as diff
FROM collectors_users
WHERE dateadded >= CURDATE() - INTERVAL 1 DAY AND
dateadded < CURDATE() + INTERVAL 1 DAY;
Note that the logic for the WHERE clause covers two days. Also, it does not use DATE(). This would allow the query to use an index, if available.

MySQL: search orders made since yesterday 3pm till today 4pm

I have table ORDERS where is stored data about orders with their status and the date of order. I would like to search all orders with specified status and which was made yesterday after 3pm untill today 4pm. The query will run in different times (10am, 3pm, 5 pm... regardless).
So on example: if I run the query today (13.05.2014) I would like to get all orders made from 2014-12-05 15:00:00 untill 13-05-2015 16:00:00
The date is stored in format: YYYY-MM-DD HH:MM:SS
What I got is:
select *
from orders
where status = 'new'
and (
(
date_add(created_at, INTERVAL 1 day) = CURRENT_DATE()
and hour(created_at) >= 15
) /*1*/
or (
date(created_at) = CURRENT_DATE()
and hour(created_at) <= 16
) /*2*/
)
And I get only orders made today - like only the 2nd condition was taken into account.
I prefer not to use created >= '2014-05-12 16:00:00' (I will not use this query, someone else will).
When you add an interval of 1 day to the date/time, you still keep the time component. Use date() for the first condition:
where status = 'new' and
((date(date_add(created_at, INTERVAL 1 day)) = CURRENT_DATE() and
hour(created_at) >= 15
) /*1*/ or
(date(created_at) = CURRENT_DATE() and
hour(created_at) <= 16
) /*2*/
)
And alternative method is:
where status = 'new' and
(created_at >= date_add(CURRENT_DATE(), interval 15-24 hour) and
created_at <= date_add(CURRENT_DATE(), interval 16 hour)
)
The advantage of this approach is that all functions are moved to CURRENT_DATE(). This would allow MYSQL to take advantage of an index on created_at.