SQL query with condition in second table - mysql

I have two tables: rooms and scheduled. In the scheduled-table, there are entries with a begin_time, end_time and a room_id - which displays when the rooms are booked. The rooms-table contains entries with an id for every room.
The begin_time and end_time only contain the hours, so for example '9' and '11', which indicate that the room is booked from 9 till 11.
I want to display a list of the rooms that are currently available. To do this, I need a query that select all room id's from the rooms table, on the condition that there is no entry in scheduled for the current hour (so the current hour does not exist between begin_time and end_time for the room id).
I tried the following:
SELECT DISTINCT id
, room_nr
FROM rooms
WHERE NOT EXISTS(SELECT room_id
FROM scheduled
WHERE rooms.id = scheduled.room_id
AND date = CURDATE()
AND HOUR(CURDATE()) NOT BETWEEN `begin_time` AND `end_time`)
But that does not work, it only shows the rooms for which the id is not existing in scheduled for the current date - without the time condition. I also tried something with joins, but I don't really understand them. How can I make a query that returns the id's from the rooms-table under the described condition?
UPDATE:
I builded the database in this MySQLFiddle: http://sqlfiddle.com/#!2/ecd82c

Try following SQL query:
SELECT DISTINCT id
, room_nr
FROM rooms
WHERE NOT EXISTS(SELECT room_id
FROM scheduled
WHERE rooms.id = scheduled.room_id
AND date = CURDATE()
AND HOUR(CURTIME()) NOT BETWEEN `begin_time` AND `end_time`)

Related

Select from 2 tables only the new entries in table 2

I got 2 tables, Customers and Payment. I'm trying to select only the new customers that have payments in the specified month and year, and no previous payments in another month.
table Customer
id - name
table Payment
id - id_customer - month - year - amount
SELECT * FROM customer, payment
WHERE Customer.id = Payment.id_customer
AND month = '$month'
AND year = '$year'
That gets me all the payments in a specific month and year, but I don't know how to exclude all the customers that had other previous payments.
Thank you for your time.
I don't think that you could achieve this without a third table. What you can do is create a third table with all the ids that you have selected in query and update it every time you run a select query.
Then the below query might work:
SELECT * FROM customer c, payment p WHERE c.id = p.id_customer
AND month = '$month'AND year = '$year'AND p.id NOT IN (SELECT id FROM
third_table)
Hope it answers your question.
To get the first date of payment, use GROUP BY. But, you will have to convert the value to something like a date first:
SELECT p.id_customer, MIN(CONCAT_WS, '-', p.year, p.month)) as first_yyyymm
FROM payment p
GROUP BY p.id_customer;
You should store the payment date as a date.

How to filter out records from one table where its id occurs in a column of another table

I have 2 MySQL tables
tableRooms contains the rooms of a hotel
tableRoomsBooked contains the booked dates of the rooms
I need an SQL query that returns the rooms that have no bookings between 2 given dates. This is what I have got so far:
SELECT * FROM `tableRooms`
LEFT JOIN `tableRoomsBooked`
ON `tableRooms`.`id` = `tableRoomsBooked`.`room_id`
WHERE (date BETWEEN '2015-01-02' AND '2015-01-30')
....?
The query should only get the room_id 2 because room 2 has no bookings in this period.
What should my query be like?
select *
from tableRooms
where id not in (
select distinct room_id
from tableRoomsBooked
where date between '2015-01-02' and '2015-01-30'
)
This will select the list of existing IDs in a sub request, then exclude them from the main request.
Anyway, you should change the name of "date" column, because "date" can be confusing as soon as it is a data type too.

MySQL using count in query to search for availability of multiple rows

I am using one table, mrp to store multi room properties and a second table booking to store the dates the property was booked on.
I thus have the following tables:
mrp(property_id, property_name, num_rooms)
booking(property_id, booking_id, date)
Whenever a property is booked, an entry is made in the bookings table and because each table has multiple rooms, it can have multiple bookings on the same day.
I am using the following query:
SELECT * FROM mrp
WHERE property_id
NOT IN (SELECT property_id FROM booking WHERE `date` >= {$checkin_date} AND `date` <= {$checkout_date}
)
But although this query would work fine for a property with a single room (that is, it only lists properties which have not been booked altogether between the dates you provide), it does not display properties that have been booked but still have vacant rooms. How can we use count and the num_rooms table to show in my results the rooms which are still vacant, even if they already have a booking between the selected dates, and to display in my results the number of rooms that are free.
You need 3 levels of query. The innermost query will list properties and dates where all rooms are fully booked (or overbooked) on any day within your date range. The middle query narrows that down to just a list of property_id's. The outermost query lists all properties that are NOT in that list.
SELECT *
FROM mrp
WHERE property_id NOT IN (
-- List all properties sold-out on any day in range
SELECT DISTINCT Z.property_id
FROM (
-- List sold-out properties by date
SELECT MM.property_id, MM.num_rooms, BB.adate
, COUNT(*) as rooms_booked
FROM mrp MM
INNER JOIN booking BB on MM.property_id = BB.property_id
WHERE BB.adate >= #checkin AND BB.adate <= #checkout
GROUP BY MM.property_id, MM.num_rooms, BB.adate
HAVING MM.num_rooms - COUNT(*) <= 0
) as Z
)
You are close but you need to change the dates condition and add a condition to match the records from the outer and inner queries (all in the inner query's WHERE clause):
SELECT * FROM srp
WHERE NOT EXISTS
(SELECT * FROM bookings_srp
WHERE srp.booking_id = bookings_srp.booking_id
AND `date` >= {$check-in_date} AND `date` <= {$check-out_date})
You have to exclude the properties which are booked between the checkin date and checkout date. This query should do:
SELECT * FROM srp WHERE property_id NOT IN (
SELECT property_id FROM booking WHERE `date` >= {$checkin_date} AND `date` <= {$checkout_date}
)

Count number of bookings between a set of specified dates

I have a table of bookings. I want to count how many bookings occur on each day, starting from specified check in date and check out date. Eg. if check in date was 10-06-2012 and check out date was 14-06-2012 I require a table like this
Date Bookings
10-06-2012 1
11-06-2012 1
12-06-2012 2
13-06-2012 4
14-06-2012 3
I am struggling to get this working. I can count bookings in between the dates but not for each date between check in date and check out date.
I am not sure I understand your question. The query below assumes:
Your bookings table has (at least) columns date, checkin, checkout.
You are looking for bookings where checkin >= 10-06-2012 and checkout <= 14-06-2012.
Here is the query:
SELECT date, COUNT(*)
FROM bookings
WHERE checkin >= '2012-06-10' AND checkout <= '2012-06-14'
GROUP BY date
Use SUM() to find total bookings between a date range.
Try Below :
SELECT Date,SUM(Bookings)
FROM tablename
WHERE Date between 'startdate' AND 'enddate'
GROUP BY Date
First thing you need is a table of dates, day by day. Now mysql is not my thing, so I will try to write down as much info on what I'm doing as I can. Please correct these examples.
Table of dates might be prepared by a job checking for the last booking date and adding missing dates to table of dates. If this is not something you would accept, other solution is to create table dynamically, but there are some perils. To my knowledge there is no way to create such a table, but you can do a practically-working surrogate by selecting distinct dates from your booking table and cross joining this with table of days made in query itself:
((select distinct checkIn from bookings union select distinct checkOut from bookings)
cross join (select 0 union select 1 union select 2 ...))
The list of days should contain as many days as the biggest gap between checkin dates and each checkin and checkout date. This is something you will have to keep an eye on, or simply make the list sufficiently large, for example a hundred days.
Now that you have a table of dates, you need to count bookings matching this date. Complete query would look like this:
select tableOfDates.date, count(bookings.checkIn) bookings
from
(
(
select distinct dates.date + INTERVAL days.day DAY -- OR HOWEVER you add days in mysql
from
(select distinct checkIn date from bookings union select distinct checkOut from bookings) dates
cross join (select 0 day union select 1 union select 2 union 3 union 4 union 5 union 6 union 7) days
)
) tableOfDates
left join bookings
on tableOfDates.date between bookings.checkIn and bookings.checkOut
where tableOfDates.date between [YOUR DATE RANGE]

MySql SUM and JOIN

I am trying to count sales made by a list of sales agents, this count is made every few minutes and updates a screen showing a 'sales leader board' which is updates using a Ajax call in the background.
I have one table which is created and populated every night containing the agent_id and the total sales for the week and month. I create a second, temporary table, on the fly which counts the sales for the day.
I need to combine the two tables to create a current list of sales for all agents in agent_count.
Table agent_count;
agent_id (varchar),
team_id (varchar),
name (varchar),
day(int),
week(int),
month(int)
Table sales;
agent_id (varchar),
day(int)
I can't figure out how to combine these tables. I think I need to use a join as all agents must be returned - even if they don't appear in the agent_count table.
First I make a simple call to get the week and month totals for all agents
SELECT agent_id, team_id, name, week, month FROM agent_count;
the I create a temporary table of todays sales, and then I count the sales for each agent for the day
CREATE TEMPORARY TABLE temp_todays_sales
SELECT s.id, s.agent_id
FROM sales s
WHERE DATEDIFF(s.uploaded, NOW()) = 0
AND s.valid = 1;
SELECT tts.agent_id, COUNT(tts.id) as today
FROM temp_todays_sales tts
GROUP BY tts.agent_id;
What is the best/easiet way to combine these to end up with a resultset such as
agent_id, team_id, name, day, week, month
where week and month also include the daily totals
thanks for any help!
Christy
SELECT s.agent_id, ac.team_id, ac.name,
s.`day` + COALESCE(ac.`day`, 0) AS `day`,
s.`day` + COALESCE(ac.`week`, 0) AS `week`,
s.`day` + COALESCE(ac.`month`, 0) AS `month`
FROM sales s
LEFT JOIN
agent_count ac
ON ac.agent_id = s.agent_id
team_id and name will be NULL if there is no record in agent_count for an agent.
If the agents can be missing from both tables, you normally would need to make a FULL JOIN but since MySQL does not support the latter you may use its poor man's substitution:
SELECT agent_id, MAX(team_id), MAX(name),
SUM(day), SUM(week), SUM(month)
FROM (
SELECT agent_id, NULL AS team_id, NULL AS name, day, day AS week, day AS month
FROM sales
UNION ALL
SELECT *
FROM agent_count
) q
GROUP BY
agent_id