check availability of room in hotel - php

There are two tables in my database. First table is room and second table is reservation. In my room table
id room_no type rate
1 13 1b 1000
2 14 2b 2000
3 15 3b 3000
4 16 1b 1000
5 17 2b 2000
6 18 3b 3000
In my reservation table
id room_no check_in check_out
1 13 23-2-2016 24-2-2016
2 14 24-2-2016 25-2-2016
1 13 25-2-2016 26-2-2016
1 13 27-2-2016 29-2-2016
1 13 1-3-2016 2-3-2016
1 13 7-3-2016 7-3-2016
"SELECT room_no,type,rate
FROM room
WHERE room_no not in
(select IFNULL(GROUP_CONCAT(room_no),0)
FROM reservation
WHERE check_out >= '$check_in' AND check_in <= '$check_out')"
when I select a date 24-2-2016 to 27-2-2016 then it display
room_no check_in check_out
14 24-2-2016 25-2-2016
15 25-2-2016 26-2-2016
16 27-2-2016 29-2-2016
17 1-3-2016 2-3-2016
18 7-3-2016 7-3-2016
but I want all available rooms.

To get occupied rooms for the period specified, i.e '2016-02-27'-'2016-02-24', you can use:
SELECT DISTINCT room_no
FROM reservation
WHERE check_in <= '2016-02-27' AND check_out >= '2016-02-24'
Output:
room_no
=======
13
14
To get available rooms you can use the previous query like this:
SELECT *
FROM room
WHERE room_no NOT IN (
SELECT DISTINCT room_no
FROM reservation
WHERE check_in <= '2016-02-27' AND check_out >= '2016-02-24')
Output:
id, room_no, type, rate
=======================
3, 15, 3b, 3000
4, 16, 1b, 1000
5, 17, 2b, 2000
6, 18, 3b, 3000
Demo here

Using a LEFT JOIN should do the trick without using a subquery.
Something like this :
SELECT
room.room_no,
room.`type`,
room.rate,
COUNT(reservation.room_no) AS countReservation
FROM
room
LEFT JOIN reservation
ON (room.room_no = reservation.room_no)
AND (check_in <= '2016-02-24' AND check_out >= '2016-01-27')
GROUP BY
room.room_no
HAVING
countReservation = 0
An other advantage in this query is the extra column countReservation that will even tell you if you have 1 or more reservations for the for the given timeframe for each room.

You should use something like this:
"SELECT room_no, type, rate
FROM room
WHERE room_no not in
(select room_no FROM reservation
WHERE ('$check_in' BETWEEN check_in AND check_out) AND ('$check_out' BETWEEN check_in AND check_out))"
I don't know if the query is correct, but you surely have to check for between.
You can't just test for check_out > than date, and check_in < date. IF you have multiple reservations this will give you Errors!!

Related

Get available and booked time in sql

I have two tables in mysql (shop_details,booking)
shop_details
id shop_id open_time close_time
1 1 09:00Am 09:00Pm
2 5 10:00Am 09:00Pm
booking
id shop_id start_time end_time
1 1 10:30am 11:10Am
1 5 02:00pm 02:45pm
Now I want if I want to know about shop_id (1) then I want to get booked time (after shop open time) and avaliable time (till shop close) with every half hour, for example I want following result
shop_id start_time end_time status
1 09:00am 09:30am avaliable
1 09:30am 10:00am avaliable
1 10:00am 10:30am avaliable
1 10:30am 11:10am booked
1 11:10am 11:40am avaliable
...
1 08:30am 09:00pm booked
You need a list of times -- then you can get the information using a join or correlated subquery:
select t.tme,
(case when exists (select 1
from booking b
where b.start_time <= t.tme and
b.end_time > t.tme
)
then 'booked' else 'available'
end) as status
from (select cast('00:00' as time) as tme union all
select cast('00:30' as time) as t union all
select cast('01:00' as time) as t union all
. . .
select cast('23:50' as time) as t
) t join
(select sd.*
from shop_details sd
where sd.shop_id = 1
) sd1
on t.tme >= sd1.open_time and
t.tme <= sd1.close_time;
first, use while function to create a loop that will repeat the code until reaching close time,
inside while function, u can use IF statement to make Availability status base on dates
goold luck

Query - Find new and repeating users in MySQL

I have a visit table with user_id and visited_at columns. I would like to find how many are new and repeat customer in this month.
user_id visited_at
--------------------------------------------------------------------------
1750 2015-04-06 10:39:20
1870 2015-04-05 15:48:11
1990 2015-04-04 12:38:35
1920 2015-04-03 10:18:21
1080 2015-04-01 10:18:21
1750 2015-01-28 12:38:59
1920 2015-01-19 17:20:20
1920 2015-01-17 15:10:10
1080 2015-01-13 20:18:41
1920 2014-04-04 10:31:15
1750 2013-10-04 10:39:20
In January 2015, user 1750 and 1920 visited the same place so total repeated customers are 2. In April 2015, user 1750, 1920 and 1080 visited the same place so total repeated customers are 3. The output should be something like this
Month New Repeat
----------------------------------------------
October 2013 1 0
April 2014 1 0
January 2015 1 2
April 2015 2 3
One approach is to get the date of the first visit for each user using a subquery. Then join in this information, and use count(distinct) to count the number of users:
select year(v.visited_at) as yyyy, month(visited_at) as mm,
count(distinct user_id) as num_users,
count(case when v.visited_at = vv.minva then user_id end) as num_new_users
from visits v join
(select user_id, min(visited_at) as minva
from visits t
group by user_id
) vv
on v.user_id = vv.user_id
group by year(v.visited_at), month(visited_at)
order by year(v.visited_at), month(visited_at);
I note that this gives the total and new users; the repeats are the difference.
Something like this will work:
SELECT * FROM table_name WHERE updated_at >= CAST('2014-02-01' AS DATE) AND updated_at <= CAST('2014-02-28' AS DATE);
SELECT
MONTH(created_at) as _Month,
YEAR(created_at) as _Year,
COUNT(*) as New
FROM
yourtable
GROUP BY 0,1
You can also filter results using where clause.

Show MySQL Count Including Zero Count with Group By Statement

I am generating mysql query to show the number of orders received in current month group by days of month.
The table structure of mysql is as follow:
order_id date
======== ==========
1234 2012-07-02
1235 2012-07-02
1236 2012-07-04
1237 2012-07-07
1238 2012-07-08
Now I want it to return following results using mysql statement
count(order_id) day
=============== ===
0 01
2 02
0 03
1 04
0 05
0 06
1 07
1 08
So on and so forth till the end of the month 30/31 depends on the days in month.
Looking forward to your suggestions and help.
Thanks.
SELECT
count(order_id),
dates.dte
FROM
(
SELECT '2011-02-01' + INTERVAL a + b DAY dte
FROM
(SELECT 0 a UNION SELECT 1 a UNION SELECT 2 UNION SELECT 3
UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7
UNION SELECT 8 UNION SELECT 9 ) d,
(SELECT 0 b UNION SELECT 10 UNION SELECT 20
UNION SELECT 30 UNION SELECT 40) m
WHERE '2011-02-01' + INTERVAL a + b DAY < '2011-03-01'
ORDER BY a + b
) dates
LEFT JOIN
orders ON orders.`date` = dates.dte
GROUP BY
dates.dte
ORDER BY
dates.dte
generate day column values in your programming language
Thanks to #The Scrum Master for nice answer here
but I also agree this shouldn't be done in database. if you think about it you actually don't need rows with 0 count.
Prepare the calendar table with a list of months and days.
To retrieve all orders from 2012-07:
select day(c.date), count(*)
from calendar c
left join orders o on c.date=o.date
where year(c.date) = 2012
and month(c.date) = 07
group by day(c.date)

calculate price between given dates

Hotel_id Room_id Room_type Start_date End_date Price
----------------------------------------------------------------
13 2 standard 2012-08-01 2012-08-15 7000
13 2 standard 2012-08-16 2012-08-31 7500
13 2 standard 2012-09-01 2012-09-30 6000
13 3 luxury 2012-08-01 2012-08-15 9000
13 3 luxury 2012-08-16 2012-08-31 10000
13 3 luxury 2012-09-01 2012-09-30 9500
Hi this is the structure and data of my table.
I need to create a mysql query for hotel booking, that would match in database user entered data:
Date when they want to checkin and checkout
Room type
For Ex:
If user selects Hotel with luxury room based on these dates (2012-08-30 to 2012-09-04)
the total cost would be (10000*2) for 30th and 31st Aug + (9500*3) for 1st,2nd and 3rd Sep(4th checkout day don't include)
that means total price will be 20000+28500=48500
So query should filter total price based on the Hotel_id,Room_id,Start_date,End_date and Price
Thanks
Use this solution:
SELECT SUM(
CASE WHEN a.Start_date = b.min_sd AND a.Start_date <> b.max_sd THEN
(DATEDIFF(a.End_date, '2012-08-30')+1) * a.Price
WHEN a.Start_date = b.max_sd AND a.Start_date <> b.min_sd THEN
DATEDIFF('2012-09-04', a.Start_date) * a.Price
WHEN (a.Start_date,a.Start_date) IN ((b.min_sd,b.max_sd)) THEN
(DATEDIFF('2012-09-04', '2012-08-30')+1) * a.Price
WHEN a.Start_date NOT IN (b.min_sd, b.max_sd) THEN
(DATEDIFF(a.End_date, a.Start_date)+1) * a.Price
END
) AS totalprice
FROM rooms a
CROSS JOIN (
SELECT MIN(Start_date) AS min_sd,
MAX(Start_date) AS max_sd
FROM rooms
WHERE Room_type = 'luxury' AND
End_date >= '2012-08-30' AND
Start_date <= '2012-09-04'
) b
WHERE a.Room_type = 'luxury' AND
a.End_date >= '2012-08-30' AND
a.Start_date <= '2012-09-04'
Replace occurances of 2012-08-30 and 2012-09-04 with your input start and end dates respectively.
This will account for start and end dates being in the same month as well as spanning across multiple months.
SQLFiddle Demo
You can use MySQL's BETWEEN ... AND ...
operator to find the date ranges in which the desired booking falls (remember to take one day off of the given checkout
date as, like you say, there is no night's stay), then group the results by room and take the
SUM() of price times number of nights (which can
be calculated using MySQL's LEAST() and
GREATEST() functions):
SELECT Room_id,
SUM(Price * (1 + DATEDIFF(
LEAST(End_date, '2012-09-04' - INTERVAL 1 DAY),
GREATEST(Start_date, '2012-08-30')
))) AS Total
FROM mytable
WHERE Room_type = 'luxury' AND (
'2012-09-04' - INTERVAL 1 DAY
BETWEEN Start_date AND End_date
OR '2012-08-30' BETWEEN Start_date AND End_date
)
GROUP BY Room_id
See it on sqlfidde.
try this:
set #Hotel_id :=13;
set #Room_id :=3;
set #Start_date :='2012-08-30' ;
set #End_date :='2012-09-04';
select sum(b.TotalPrice-b.deductions) as total_cost from
( select a.Price,a.StartDate,a.EndDate,price*(DATEDIFF(a.EndDate,a.StartDate)+1) as TotalPrice
,case when a.EndDate=#End_date then a.Price else 0 end as deductions
from
(select price,case when #Start_date>=Start_date then #Start_date else Start_date end as StartDate
,case when #End_date<=End_date then #End_date else End_date end as EndDate
from h_booking h1
where Hotel_id=#Hotel_id
and Room_id=#Room_id
and (#Start_date between Start_date and End_date or #End_date between Start_date and End_date ))a )b

mysql crosstab query into php array - instead of three sql queries

I'd like to select sum of three columns from three tables in mysql and then get it as php array.
Tables:
Amex:
incr_id,check_no, card_no, tip, total, date;
Mc:
incr_id,check_no, card_no, tip, total, date;
Visa
incr_id,check_no, card_no, tip, total,date ;
Pseudo code :
$query =
select sum(tip) from Amex,
select sum(tip) from Mc,
select sum(tip) from Visa
WHERE DATE(date) = CURDATE()
mysql_fetch_array($query);
and then 'foreach' or 'while' to get three values into php array:
$ccpayments_tip['Amex']
$ccpayments_tip['Mc']
$ccpayments_tip['Visa']
Is this possible or I will have to execute three select queries?
Thanks!
You can use a Union query to do all three at once, with a derived field to indicate which table the sums are coming from:
$sql = <<<EOL
SELECT 'Amex' AS source, SUM(tip) AS sum FROM Amex
UNION
SELECT 'MC' AS source, SUM(tip) AS sum FROM Mc
UNION
SELECT 'Visa' AS source, SUM(tip) AS sum FROM Visa
EOL;
$result = mysql_query($sql) or die(mysql_error());
$ccpayments_tip = array();
while($row = mysql_fetch_assoc($result)) {
$ccpayments_tip[$row['source']] = $row['sum'];
}
Of course, why do you have 3 seperate tables for this? Wouldn't it make more sense to have a single creditcard table with a type field to indicate if it's visa/amex/mc?
You could do a union of the three queries.
You could try something like this
http://dev.mysql.com/doc/refman/5.0/en/from-clause-subqueries.html
Pseudo
SELECT A.Amex, M.MC, V.Visa
FROM
(SELECT SUM(tip) AS Amex FROM Amex WHERE DATE(date) = CURDATE()) AS A,
(SELECT SUM(tip) AS Mc FROM Mc WHERE DATE(date) = CURDATE()) AS M,
(SELECT SUM(tip) AS Visa FROM Visa WHERE DATE(date) = CURDATE()) AS V
UPDATE: Pseudo Code as well
/*
'*CARD TYPES *PREFIX *WIDTH
'American Express 34, 37 15
'Diners Club 300 to 305, 36 14
'Carte Blanche 38 14
'Discover 6011 16
'EnRoute 2014, 2149 15
'JCB 3 16
'JCB 2131, 1800 15
'Master Card 51 to 55 16
'Visa 4 13, 16
*/
SELECT SUM(tip), CASE
WHEN card_no >= 4 AND card_no <= 5 THEN 'visa'
WHEN card_no >= 51 AND card_no <= 56 THEN 'mc'
WHEN card_no >= 34 AND card_no <= 38 THEN 'amex'
ELSE NULL
END AS credit_card_type
FROM Amex, Mc, Visa
WHERE DATE(date) = CURDATE()
GROUP BY CASE
WHEN card_no >= 4 AND card_no <= 5 THEN 'visa'
WHEN card_no >= 51 AND card_no <= 56 THEN 'mc'
WHEN card_no >= 34 AND card_no <= 38 THEN 'amex'
ELSE NULL
END AS credit_card_type
Haven't tested either query just a example to maybe think outside of the box
UPDATE from your comment:
If you're going to move to a transaction database and store the card_type you could use a query like this:
SELECT SUM(tip)
FROM transaction_tbl
WHERE DATE(date) = CURDATE()
GROUP BY card_type

Categories