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
Related
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'
everyone!
I'm trying to calc sum of price of deals by each day. What i do:
SET #symbols_set = "A,B,C,D";
DROP TABLE IF EXISTS temp_deals;
CREATE TABLE temp_deals AS SELECT Deal, TimeMsc, Price, VolumeExt, Symbol FROM deals WHERE TimeMsc >= "2019-04-01" AND TimeMsc <= "2019-06-30" AND FIND_IN_SET(Symbol, #symbols_set) > 0;
SELECT
DATE_FORMAT(TimeMsc, "%d/%m/%Y") AS Date,
Symbol,
(SELECT SUM(Price) FROM temp_deals dap WHERE dap.TimeMsc BETWEEN Date AND Date + INTERVAL 1 DAY AND dap.Symbol = Symbol) AS AvgPrice
FROM temp_deals
ORDER BY Date;
DROP TABLE IF EXISTS temp_deals;
But in result i've got NULL in AvgPrice column. I can't understand what i'm doing wrong.
It's look like i can't pass parent query's column to subquery, am i right?
Qualify your column names. But mostly, don't use a string for comparing dates:
SELECT DATE_FORMAT(d.TimeMsc, '%d/%m/%Y') AS Date,
d.Symbol,
(SELECT SUM(dap.Price)
FROM temp_deals dap
WHERE dap.TimeMsc >= d.TimeMsc AND
dap.TimeMsc < d.TimeMsc + INTERVAL 2 DAY AND -- not sure if you want 1 day or 2 day
dap.Symbol = d.Symbol
) AS AvgPrice
FROM temp_deals d
ORDER BY d.TimeMsc;
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
I have a query in which I would like to return the number of users who have logged in for the month without repeating the record in the next month.
If a user has logged in April and May, it only shows one record for April. This is what I have so far.
SELECT DISTINCT (a.userid), EXTRACT(MONTH FROM a.loginTime) as month
FROM login_audit a LEFT JOIN user u on u.userid = a.userid
WHERE a.loginTime <= '2012-12-31 11:59:59'
AND a.loginTime >= '2012-01-01 00:00:00'
GROUP BY month
So far the records are returning
userid month
1 1
2 1
1 2
3 2
In this scenario, user 1 is coming up for both January and Februray. I would like it to ommit that record. Either that or have it accumulated. Like so:
Either
userid month
1 1
2 1
3 2
Or
userid month
1 1
2 1
1 2
2 2
3 2
I hope this made sense. Please ask me anything if you'd like any further clarifications. Thanks a lot!
Don't see where you need table user...
For first "wanted scenario" :
SELECT
a.userid,
MIN(EXTRACT(MONTH FROM a.loginTime)) as month
FROM login_audit a
WHERE a.loginTime <= '2012-12-31 11:59:59' AND a.loginTime >= '2012-01-01 00:00:00'
GROUP BY a.userid
I would use this approach.
SELECT DISTINCT (a.userid), EXTRACT(MONTH FROM a.loginTime) as month
FROM login_audit a
WHERE a.loginTime <= '2012-12-31 11:59:59'
AND a.loginTime >= '2012-01-01 00:00:00'
and not exists
(select userid
from login_audit
where login_audit.user_id = a.user_id
and carry on with date range for the following month
)
Hello i have 2 tables rooms and bookings but my table sturcture little bit different,
in bookings table there are roomid,date,status for example:
101,2012-12-10,0
101,2012-12-11,0
101,2012-12-12,1
101,2012-12-13,0
102,2012-12-10,0
102,2012-12-11,0
102,2012-12-12,0
and i would like to find available rooms between 2012-12-10 and 2012-12-13
according this request only room 102 should be return.
i've tried
SELECT id
FROM status
WHERE status='0'
AND date between '2012-12-10' AND '2012-12-13'
GROUP BY id
it doesn't work because even find only one available row it returns true for 101
so 101 is available for 2012-12-11 then showing like available but not okay for our data range.
This will select all rooms that have no row with status=1 in the interval you select. Notice that I am not using between: if status=1 on 13th of December, the room is still available in the interval, that's why I'm using >= and <:
SELECT roomid
FROM status
WHERE `date` >= '2012-12-10'
AND `date` < '2012-12-13'
GROUP BY roomid
HAVING sum(status.status=1)=0
If there could also be some missing days in your table, and if that means that the room is not booked but also not available, you could also use this query:
SELECT roomid
FROM status
WHERE `date` >= '2012-12-10'
AND `date` < '2012-12-13'
AND status=0
GROUP BY roomid
HAVING count(*)=DATEDIFF('2012-12-13', '2012-12-10')
that checks that the number of days in the interval is equal to the number of rows with status=0.
If the date has a time associated with it you need to do something like this:
SELECT id
FROM status
WHERE status='0'
AND date between '2012-12-10 00:00:00' AND '2012-12-13 23:59:59'
GROUP BY id
You can also use Date(date) instead of including times, but this might be less efficient.
You should be able to use the following:
SELECT roomid
FROM status s1
WHERE status='0'
AND date between '2012-12-10' AND '2012-12-13'
and not exists (select roomid
from status s2
where status='1'
AND date between '2012-12-10' AND '2012-12-13'
and s1.roomid = s2.roomid)
GROUP BY roomid
See SQL Fiddle with demo
Try this:
SELECT rd.*
FROM room_details rd
INNER JOIN (SELECT DISTINCT roomid FROM bookings
WHERE roomid NOT IN (SELECT roomid FROM bookings
WHERE STATUS =0 AND DATE BETWEEN '2012-12-10' AND '2012-12-13')
) AS a ON rd.roomid = a.roomid
The SQL BETWEEN condition will return the records where expression is within the range of value1 and value2 (inclusive). So row 101,2012-12-10,0 should be returned for above mentioned query.
Try this:
SELECT roomid
FROM status
WHERE 'date_from' <= "2012-12-10" AND 'date_to' > "2012-12-10" AND 'status'= 0;