How to get results not between two dates? - mysql

I have two dates that property has been blocked on that two days like start date 2017-01-20 and end end 2017-01-25. Between these two dates property has been blocked. When I search with these two dates except these two dates I want to get the remaining dates.
Here I have tried by searching the web in MySQL like
select `pd`.*, `pa`.*
from `property_details` as `pd` left join
`property_gallery` as `pg`
on `pg`.`property_id` = `pd`.`property_id` left join
`property_preblock_details` as `pbd`
on `pbd`.`property_id` = `pd`.`property_id` left join
`property_amenity` as `pa`
on `pa`.`property_id` = `pd`.`property_id`
where `pbd`.`start_date` >= '2017-01-20' and `pbd`.`end_date` <= '2017-01-25'
and
select pd.* from
`property_details` as `pd` left join
`property_gallery` as `pg` on `pg`.`property_id` = `pd`.`property_id`
left join `property_preblock_details` as `pbd`
on `pbd`.`property_id` = `pd`.`property_id`
left join `property_amenity` as `pa`
on `pa`.`property_id` = `pd`.`property_id`
where `pbd`.`start_date` NOT BETWEEN CAST('2017-01-20' AS DATE) and CAST('2017-01-25' AS DATE)
AND `pbd`.`end_date` NOT BETWEEN CAST('2017-01-20' AS DATE) and CAST('2017-01-25' AS DATE)
But I'm getting results as between dates.
I don't want to get between dates results, I want to get not between dates results.
Property_rate
id start_date end_date prop_id
1 2017-01-20 2017-01-25 1
2 2017-01-26 2017-01-27 1
3 2017-01-26 2017-01-28 2
Property
prop_id prop_name
1 test1
2 test2
If I select 2017-01-20 and 2017-01-25, I want to get 'test2' property details only. Not 'test1' details.

You've very close. Your query says this:
where `pbd`.`start_date` >= '2017-01-20' /* close, but wrong */
and `pbd`.`end_date` <= '2017-01-25'
What you want is this:
where ( `pbd`.`start_date` < '2017-01-20'
or `pbd`.`end_date` > '2017-01-25')
It can also be written
where not ( `pbd`.`start_date` >= '2017-01-20'
and `pbd`.`end_date` <= '2017-01-25')
BEWARE Your query may have another mistake in it. If your start_date and end_date columns have the DATE data type, you're all set. But if they have another data type, such as DATETIME or TIMESTAMP, your query has another problem. To catch all the rows with date/time values on the days 20-Jan-2017 -- 25-Jan-2017 you need this
where `pbd`.`start_date` >= '2017-01-20' /*dates IN range */
and `pbd`.`end_date` < '2017-01-26'
Notice I moved the desired end date one day later and used < instead of <=. This works correctly for
2017-01-25 23:59 should be in range
2017-01-26 00:00 should be out of range
2017-01-26 00:01 should be out of range

Try:
SELECT *
FROM `Table`
WHERE `DATECOLUMN` NOT
IN (
SELECT 'ID'
FROM `Table`
WHERE `DATECOLUMN`
BETWEEN (
'2017-02-10 00:00:00'
)
AND (
'2017-09-14 00:00:00'
)
)
LIMIT 0 , 30

Related

How should I use NOT IN statement in MySQL

I am trying to use NOT IN statement with MySQL. However, I get 0 row with code below (no syntax error). I am sure there should be more than 0 row with the statement. What syntax should I adjust?
SELECT DISTINCT member_id
FROM client_payments
INNER JOIN client_purchase_records ON client_purchase_records.id = client_payments.purchase_record_id
WHERE status = 1
AND client_payments.created_at > '2021-10-28 00:00:00'
AND client_payments.created_at < '2021-10-31 23:59:00'
NOT IN(
SELECT DISTINCT member_id
FROM client_payments
INNER JOIN client_purchase_records ON client_purchase_records.id = client_payments.purchase_record_id
WHERE status = 1
AND client_payments.created_at > '2020-9-30 00:00:00'
AND client_payments.created_at < '2021-10-27 23:59:00'
);
Difference about two query is mainly about created_at column, I want to do "set difference operation" with period A(2021-10-28 00:00:00 - 2021-10-31 23:59:00 )and period B(2020-9-30 00:00:00 - 2021-10-27 23:59:00)
I want to query out member_id who pay during 2020-9-30 00:00:00 - 2021-10-27 23:59:00
Subtract with member_id who pay during 2021-10-28 00:00:00 - 2021-10-31 23:59:00
Finally I get member_id who pay during 2021-10-28 00:00:00 - 2021-10-31 but not pay during 2020-9-30 00:00:00 - 2021-10-27 23:59:00 ( new member_id never show before)
no syntax error
The error is in the logic.
Your condition, after adding the parenthesis according to operators priority, looks like
AND ( (client_payments.created_at < '2021-10-31 23:59:00') NOT IN ( {subquery} ) )
I.e. the result of comparing client_payments.created_at < '2021-10-31 23:59:00' (which is 0, 1 or NULL) is searching in the subquery output which is obviously illogical.
You presumably want to be saying AND member_id NOT IN (...your subquery...); as is, it is using the previous condition instead of member_id.
Also, it looks like you want >= and <=, not > and <.
I would do this like so instead:
SELECT member_id
FROM client_payments
INNER JOIN client_purchase_records ON client_purchase_records.id = client_payments.purchase_record_id
WHERE status = 1
AND client_payments.created_at >= '2021-09-30 00:00:00'
AND client_payments.created_at <= '2021-10-31 23:59:00'
GROUP BY member_id
HAVING MIN(client_payments.created_at) >= '2021-10-28 00:00:00'

MYSQL join with where clause excluding matching value

I am confused with a basic query, I have 2 tables employees and employee_time_off. I wanted to fetch all those employees who are not off on any specific date.
What I have tried is,
SELECT
employees.id,
employees.FIRST_NAME
FROM `employees`
LEFT JOIN `employee_time_off` ON `employees`.`id` = `employee_time_off`.`employee_id`
AND `START_DATE` < '2019-06-30 00:00:00' AND `END_DATE` > '2019-06-30 12:59:59'
START_DATE is actually when the leaves start, END_DATE is when the leave ends.
So, in this case, employee with id=1 shouldn't be in the result set. But the result set gets all the employees from 1 to 6.
How about NOT EXISTS?
SELECT e.*
FROM employees e
WHERE NOT EXISTS (SELECT 1
FROM employee_time_off eto
WHERE eto.employee_id = e.id AND
eto.start_date <= '2019-06-30' AND
eto.end_date >= '2019-07-01'
);
Note: I'm not sure if the end_date should be '2019-06-30' or '2019-07-01'. Your question doesn't have enough information (off the whole day or any part of the day).
Your version returns all employees because you are using a LEFT JOIN.
from the SQL, we can't tell which table has the start_date and end_date columns. we suspect its the employee_time_off table. to reduce ambiguity, qualify all column references
We can add a condition to the WHERE clause, to throw out the rows where we find a matching row in time off. Also looks like we need to do <= and >= comparisons to get the result we're after.
SELECT e.id
, e.first_name
FROM employees e
LEFT
JOIN employee_time_off o
ON o.employee_id = e.id
AND o.start_date <= '2019-06-30 00:00:00'
AND o.end_date >= '2019-06-30 23:59:59'
WHERE o.employee_id IS NOT NULL
Note that with that query, we would get a different result if we had these rows in the time_off table:
employee_id start_date end_date
----------- ---------------- -------------------
1 2019-06-30 00:00:00 2019-06-30 07:24:59
1 2019-06-30 07:25:00 2019-06-30 23:59:59
What should the query return when time off table contains a row like this?
employee_id start_date end_date
----------- ---------------- -------------------
2 2019-06-29 00:00:00 2019-06-30 11:14:59
The specification isn't clear.
Also, we tend to do datetime overlap checks with conditions like
WHERE foo >= '2019-06-30 00:00'
AND foo < '2019-06-30 00:00' + INTERVAL 1 DAY

SQL query from time_in column but not from time_out column

I'm using mysql. I have a table time_record. There are four columns namely id, time_in, time_out and students_id. I only want to query the record of the latest time_in of the student but if the latest record of the student is in time_out, it will not query. How do I query the student's latest time_in record if given that the student still does not times out?
Thanks
Here is my sample code (though it returns both records from timein and timeout)
select concat (
st.student_fname,
' ',
st.student_lname
) as 'Name',
t.students_id,
t.time_in,
t.time_out,
case
when t.time_in > t.time_out
then t.time_in
else t.time_out
end as MostRecentDate
from classes c
join student_classes s on c.id = s.classes_id
join timerecords t on t.students_id = s.students_id
join students st on s.students_id = st.student_id
where c.employees_id = 'sessionvalue2'
and
where date (t.time_in) between date (now()) and date (now())
From what I understand, you want to query all results in which time_in is the latest entry and exclude results where time_out is the latest entry.
Try this:
SELECT DISTINCT(tr.id), tr.time_in
FROM time_record tr
WHERE tr.time_in > tr.time_out
ORDER BY tr.time_in DESC
I think your time_out columns may have nulls due to which the comparison results in false in that case and it return time_out.
Also,
date (t.time_in) between date (now()) and date (now())
doesn't make any sense. If you want to check the time_in for today's date, do:
date(t.time_in) = curdate();
Use curdate() instead of date(now()).
or Sargable so that index can be used if any:
date >= curdate()
and date < date_add(curdate(), interval 1 day)
Try flipping the condition like this:
select concat (
st.student_fname,
' ',
st.student_lname
) as 'Name',
t.students_id,
t.time_in,
t.time_out,
case
when t.time_in < t.time_out
then t.time_out
else t.time_in
end as MostRecentDate
from classes c
join student_classes s on c.id = s.classes_id
join timerecords t on t.students_id = s.students_id
join students st on s.students_id = st.student_id
where c.employees_id = 'sessionvalue2'
and date >= curdate()
and date < date_add(curdate(), interval 1 day)

Getting total average between dates

I have a table named sales with the following format.
sale_id user_id sale_date sale_cost
j847bv-6ggd bd48ta36-cn5x 2017-01-10 15:43:12 30
vf87x2-15gr bd48ta36-cn5x 2017-01-05 13:41:16 60
3gfd7f-2cdd 8g4f5ccf-1fet 2017-01-15 14:10:12 100
4bgfd5-12vn 8g4f5ccf-1fet 2017-01-20 19:47:14 20
b58e32-bf87 8g4f5ccf-1fet 2017-01-20 17:35:13 15
bg87db-127g gr4gg1f4-3gbb 2017-01-20 12:26:15 80
How could I get the average amount that a user (user_d) spends within the first X amount of days since their first purchase? I don't want an average for every user, but a total average for all.
I know that I can get the average using select avg(sale_cost) but I'm unsure how to find out the average for a date period.
You can find average of total for each user within 10 days date range from intial sales date like this:
select avg(sale_cost)
from (
select sum(t.sale_cost) sale_cost
from your_table t
join (
select user_id, min(sale_date) start_date, date_add(min(sale_date), interval 10 day) end_date
from your_table
group by user_id
) t2 on t.user_id = t2.user_id
and t.sale_date between t2.start_date and t2.end_date
group by t.user_id
) t;
It finds the first sale_date and date 10 days after this for each user. Then joins it with the table to get total for each user within that range and then finally average of the above calculated totals.
Demo
If you want to find the average between overall first sale_date (not individual) and 10 days from it, use:
select avg(sale_cost)
from (
select sum(t.sale_cost) sale_cost
from your_table t
join (
select min(sale_date) start_date, date_add(min(sale_date), interval 10 day) end_date
from your_table
) t2 on t.sale_date between t2.start_date and t2.end_date
group by t.user_id
) t;
Demo
The between operator comes in handy whenever it comes to checking ranges
SELECT column_name(s)
FROM table_name
WHERE column_name BETWEEN value1 AND value2;
In this case value1 and value2 will be replaced by your dates using:
'2011-01-01 00:00:00' AND '2011-01-31 23:59:59'
or
sale_date AND DATE_ADD(OrderDate,INTERVAL 10 DAY)
The first way is faster and also the between values are inclusive.

Count number of entries in time interval 1 that appear in time interval 2 - SQL

I am new here and tried to look up the answer to my question but couldn't find anything on it. I am currently learning how to work with SQL queries and am wondering how I can count the amount of unique values that appear in two time intervals?
I have two columns; one is the timestamp while the other is a customer id. What I want to do is to check, for example, the amount of customers that appear in time interval A, let's say January 2014 - February 2014. I then want to see how many of these also appear in another time interval that i specify, for example February 2014-April 2014. If the total sample were 2 people who both bought something in january while only one of them bought something else before the end of April, the count would be 1.
I am a total beginner and tried the query below but it obviously won't return what I want because each entry only having one timestamp makes it not possible to be in two intervals.
SELECT
count(customer_id)
FROM db.table
WHERE time >= date('2014-01-01 00:00:00')
AND time < date('2014-02-01 00:00:00')
AND time >= date('2014-02-01 00:00:00')
AND time < date('2014-05-01 00:00:00')
;
Try this.
select count(distinct t.customer_id) from Table t
INNER JOIN Table t1 on t1.customer_id = t.customer_id
and t1.time >= '2014-01-01 00:00:00' and t1.time<'2014-02-01 00:00:00'
where t.time >='2014-02-01 00:00:00' and t.time<'2014-05-01 00:00:00'
Here's one method of doing this with conditional grouping in an inner-select.
Select Case
When GroupBy = 1 Then 'January - February 2014'
When GroupBy = 2 Then 'February - April 2014'
End As Period,
Count (Customer_Id) As Total
From
(
SELECT Customer_Id,
Case
When Time Between '2014-01-01' And '2014-02-01' Then 1
When Time Between '2014-02-01' And '2014-04-01' Then 2
Else -1
End As GroupBy
From db.Table
) D
Where GroupBy <> -1
Group By GroupBy
Edit: Sorry, misread the question. This will show you those that overlap those two time ranges:
Select Count(Customer_Id)
From db.Table t1
Where Exists
(
Select Customer_Id
From db.Table t2
Where t1.customer_id = t2.customer_id
And t2.Time Between '2014-02-01' And '2014-04-01'
)
And t1.Time Between '2014-01-01' And '2014-02-01'