How to get hotel total room and booked room in single query - mysql

How to get hotel total room and booked room in single query.
I used 2 queries get result. I need this in single query.
The issue I am experiencing since all counts are in this table htl_room_information.id_hotel
Booked room:
SELECT x.hotel_name
, count(i.id_hotel) room
FROM htl_booking_detail d
JOIN htl_branch_info_lang x
ON x.id=d.id_hotel
JOIN htl_room_information i
ON d.id_room=i.id
group
by x.hotel_name;
+------------------------------------------+------+
| hotel_name | room |
+------------------------------------------+------+
| hotel | 3 |
| hotel1 | 1 |
| hotel2 | 4 |
| hotel3 | 13 |
| hotel4 | 9 |
| hotel5 | 3 |
| hotel6 | 3 |
| hotel7 | 2 |
+------------------------------------------+------+
Total Rooms
SELECT (htl_branch_info_lang.hotel_name) as hotel_name,count(htl_room_information.id_hotel) as total_room FROM htl_room_information ,htl_branch_info_lang where htl_room_information.id_hotel=htl_branch_info_lang.id group by htl_branch_info_lang.hotel_name;
+------------------------------------------+------------+
| hotel_name | total_room |
+------------------------------------------+------------+
| hotel | 219 |
| hotel2 | 25 |
| hotel3 | 16 |
| hotel4 | 5 |
| hotel5 | 55 |
| hotel6 | 27 |
| hotel7 | 56 |
| hotel8 | 52 |
+------------------------------------------+------------+

Use dependent subqueries.
SELECT x.hotel_name,
(
SELECT count(i.id_hotel)
FROM htl_booking_detail d
JOIN htl_room_information i
ON d.id_room=i.id
WHERE x.id=d.id_hotel
) as room,
(
SELECT count(i.id_hotel)
FROM htl_room_information i
WHERE i.id_hotel=x.id
) as total_room
FROM htl_branch_info_lang x
I assume that the hotel_name is unique in the htl_branch_info_lang table. If not, you have to put distinct behind the first SELECT.

Hoping, I understood your question correctly.
Please check below query.
select b.hotel_name hotel_name, a.room ,
b.total_room
from
(SELECT htl_branch_info_lang.hotel_name,
count(htl_room_information.id_hotel) as room FROM htl_booking_detail,
htl_branch_info_lang, htl_room_information WHERE
htl_branch_info_lang.id=htl_booking_detail.id_hotel and
htl_booking_detail.id_room=htl_room_information.id group by
htl_branch_info_lang.hotel_name ) a RIGHT join (SELECT (htl_branch_info_lang.hotel_name) as
hotel_name,count(htl_room_information.id_hotel) as total_room
FROM htl_room_information ,htl_branch_info_lang
where htl_room_information.id_hotel=htl_branch_info_lang.id
group by htl_branch_info_lang.hotel_name) b
on a.hotel_name = b.hotel_name
;

You can use subquery
try this:
SELECT (a.hotel_name) as
hotel_name,count(htl_room_information.id_hotel) as total_room, (SELECT
count(htl_room_information.id_hotel) as room FROM htl_booking_detail,
htl_branch_info_lang b, htl_room_information WHERE
b.id=htl_booking_detail.id_hotel and
htl_booking_detail.id_room=htl_room_information.id and
b.hotel_name = a.hotel_name), count(htl_room_information.id_hotel) - (SELECT
count(htl_room_information.id_hotel) as room FROM htl_booking_detail,
htl_branch_info_lang b, htl_room_information WHERE
b.id=htl_booking_detail.id_hotel and
htl_booking_detail.id_room=htl_room_information.id and
b.hotel_name = a.hotel_name) as available FROM htl_room_information
,htl_branch_info_lang
a where htl_room_information.id_hotel=a.id group by
a.hotel_name;

Related

Joining 4 Tables together and checking where totals do not match

I have 4 tables act,up, pos_act, pos_up
In this example, let's say I have customer ID and Amount columns as
act.cust_id, up.cust_id, act.amount, up.amount
pos_up.cID, pos_act.cID, pos_up.amount_, pos_act.amount_
act
| cust_id | amount |
|:-------:|:------:|
| 6789 | 30.00 |
| 9876 | 25.00 |
pos_act
| cID | amount_|
|:-------:|:------:|
| 6789 | 30.00 |
| 9876 | 24.99 |
----------------------------------------
up
| cust_id | amount |
|:-------:|:------:|
| 1234 | 10.00 |
| 2345 | 75.00 |
pos_up
| cID | amount_|
|:-------:|:------:|
| 1234 | 9.99 |
| 2345 | 75.00 |
Now With this, I want to compare where amounts do not match all in one table.
So in this example 2345 matches in up but in act 1234 does not match.
Then the results should be
All Unmatched
| cust_id | Table |
|:-------:|:------:|
| 9876 | Act |
| 1234 | Up |
I tried with unions but cant seem to get that working
SELECT *
FROM (
select cID, amount FROM act as a
union select cID, amount FROM up as b
) as v
LEFT JOIN
(select CID, amount_ FROM pos_up as c
UNION select CID, amount_ from pos_act as d
) as r
WHERE a.amount != d.amount_
I also tried with left joins but it just shows me all results. I only want ones that do not match. custid is a unique ID and may appear multiple times.
You just use UNION in a wrong place
SELECT cID, amount, 'act' as `table`
FROM act as a
LEFT JOIN pos_act as pa
ON a.cust_id = pa.
WHERE a.amount != pa.amount_
UNION ALL
SELECT cID, amount, 'up'
FROM up as u
LEFT JOIN pos_up as pu
ON u.cust_id = pu.cID
WHERE u.amount != pu.amount_

i want to show an one particular blog have how much likes and how much comment using sql query

Blog table:
| bid | btitle |
| 29 | ...... |
| 38 | ...... |
likes table:
| lid | bid |
| 1 | 29 |
| 2 | 29 |
| 3 | 29 |
| 4 | 38 |
| 5 | 38 |
comment table
| commid | bid |
| 1 | 29 |
| 2 | 29 |
| 3 | 38 |
I had tried the following query but that will not work for me:
SELECT blog.bid,blog.btitle,COUNT(likes.lid) AS likecnt,COUNT(comment.comid) AS commentcnt FROM blog,likes,comment WHERE blog.bid=likes.bid AND blog.bid=comment.bid GROUP BY blog.bid
i want output like:
| bid | btitle | likecnt | commentcnt |
| 29 | ...... | 3 | 2 |
| 38 | ...... | 2 | 1 |
You can do left join with separate aggregation :
select b.bid, b.btitle,
coalesce(l.likecnt, 0) as likecnt,
coalesce(c.commentcnt, 0) as commentcnt
from blog b left join
(select l.bid, count(*) as likecnt
from likes l
group by l.bid
) l
on l.bid = b.bid left join
(select c.bid, count(*) as commentcnt
from comment c
group by c.bid
) c
on c.bid = l.bid;
If you want only matching bids the use INNER JOIN instead of LEFT JOIN & remove COALESCE().
Under many circumstances, correlated subqueries may be the fastest solution:
select b.bid, b.btitle,
(select count(*) from likes l where l.bid = b.bid) as num_likes,
(select count(*) from comment c where c.bid = b.bid) as num_comments
from blog b;
When is this a win performance wise. First, you want indexes on likes(bid) and comments(bid). With those indexes, it might be the fastest approach for your query.
It is particularly better if you have a where clause filtering the blogs in the outer query. It only has to do the counts for the blogs in the result set.
Use proper joins and count DISTINCT values because multiple joins increase the number of returned rows:
SELECT b.bid, b.btitle,
COUNT(DISTINCT l.lid) AS likecnt,
COUNT(DISTINCT c.comid) AS commentcnt
FROM blog b
LEFT JOIN likes l ON b.bid = l.bid
LEFT JOIN comment c ON b.bid = c.bid
GROUP BY b.bid, b.btitle
See the demo.
I use LEFT joins just in case there are no comments or likes for a post.
Results:
| bid | btitle | likecnt | commentcnt |
| --- | ------ | ------- | ---------- |
| 29 | ...... | 3 | 2 |
| 38 | ...... | 2 | 1 |

SQl - find average amount per person

I have two tables
class
| id | area | students |
| 1 | area1 | 2 |
| 2 | area1 | 28 |
| 3 | area1 | 22 |
| 4 | area2 | 4 |
deliveries
| id | kg | classid |
| 1 | 120 | 1 |
| 2 | 80 | 1 |
| 3 | 20 | 1 |
| 4 | 200 | 2 |
| 5 | 150 | 3 |
| 6 | 14 | 2 |
I need to sum up the average of kg delivered per student in a each area.
For area1 that should amount to (120+80+20+200+150+14)/(2+28+22) = 11.23
But I can't figure out how to write that query. I guess I have to use some kind of subquery to first sum out students in area1 (52), before I sum kg delivered and divide on students?
This is a little tricky, because the students should be counted separately from the classes:
select c.area, sum(d.kg) / max(area_students) as avg_kg_per_student
from class c join
deliveries d
on d.classid = c.id join
(select c2.area, sum(students) as area_students
from class c2
group by c2.area
) c2
on c2.area = c.area
group by c.area;
I think you cannot use average because you need to determine the denominator yourself:
SELECT sum(kg)/ studSum AS avg
FROM _class LEFT JOIN _deliveries ON _class.id=_deliveries.classid
left join (select area, sum(students) as studSum from _class group by area) subT
ON subT.area=_class.area
GROUP BY _class.area;
Here is a very readable approach: Get students per area and kg per area, then join the two.
select stu.area, stu.students, del.kg, del.kg / stu.students
from
(
select area, sum(students) as students
from class
group by area
) stu
join
(
select c.area, sum(d.kg) as kg
from class c
join deliveries d on d.classid = c.classid
group by c.area
) del on del.area = stu.area;

Using left join with min

I am trying to connect two tables with left join and a date.
My SQL Query
SELECT
ord.`ordernumber` bestellnummer,
his.`change_date` zahldatum
FROM
`s_order` ord
LEFT JOIN
`s_order_history` his ON ((ord.`id`=his.`orderID`) AND (ord.`cleared`=his.`payment_status_id`)) #AND MIN(his.`change_date`)
WHERE
ord.`ordertime` >= \''.$dateSTART.'\' AND ord.`ordertime` <= \''.$dateSTOP.'\'' ;
s_order
+----+---------------------+---------+-------------+
| id | ordertime | cleared | ordernumber |
+----+---------------------+---------+-------------+
| 1 | 2014-08-11 19:53:43 | 2 | 123 |
| 2 | 2014-08-15 18:33:34 | 2 | 125 |
+----+---------------------+---------+-------------+
s_order_history
+----+-------------------+-----------------+---------+---------------------+
| id | payment_status_id | order_status_id | orderID | orderID change_date |
+----+-------------------+-----------------+---------+---------------------+
| 1 | 1 | 5 | 1 | 2014-08-11 20:53:43 |
| 2 | 2 | 5 | 1 | 2014-08-11 22:53:43 |
| 3 | 2 | 7 | 1 | 2014-08-12 19:53:43 |
| 4 | 1 | 5 | 2 | 2014-08-15 18:33:34 |
| 5 | 1 | 6 | 2 | 2014-08-16 18:33:34 |
| 6 | 2 | 6 | 2 | 2014-08-17 18:33:34 |
+----+-------------------+-----------------+---------+---------------------+
Wanted result:
+-------------+---------------------+
| ordernumber | change_date |
+-------------+---------------------+
| 123 | 2014-08-11 22:53:43 |
| 125 | 2014-08-17 18:33:34 |
+-------------+---------------------+
The problem I have is getting only the date, where the cleared/payment_status_id value has been changed in s_order. I currently get all dates where the payment_status_id matches the current cleared value, but I only need the one, where it happend first.
This is only an excerpt of the actually query, since the original is a lot longer (mostly more left joins and a lot more tables).
You can group data by ordernumber
SELECT
ord.`ordernumber` bestellnummer,
MIN(his.`min_change_date`) as zahldatum
FROM
`s_order` ord
LEFT JOIN
`s_order_history` his ON ((ord.`id`=his.`orderID`) AND (ord.`cleared`=his.`payment_status_id`)) #AND MIN(his.`change_date`)
WHERE
ord.`ordertime` >= \''.$dateSTART.'\' AND ord.`ordertime` <= \''.$dateSTOP.'\''
GROUP BY
ord.`ordernumber`;
or you can group data in a subquery:
SELECT
ord.`ordernumber` bestellnummer,
his.`min_change_date` zahldatum
FROM
`s_order` ord
LEFT JOIN (
SELECT
orderID, payment_status_id, MIN(change_date) as min_change_date
FROM
s_order_history
GROUP BY
orderID, payment_status_id
) his ON (ord.`id` = his.`orderID` AND ord.`cleared` = his.`payment_status_id`)
WHERE
ord.`ordertime` >= \''.$dateSTART.'\' AND ord.`ordertime` <= \''.$dateSTOP.'\'';
Try this:
select s_order.ordernumber, min(s_order_history.change_date)
from s_order left join s_order_history
on s_order.id = s_order_history.orderID
and s_order.cleared = s_order_history.payment_status_id
group by s_order.order_id
SELECT ord.`ordernumber` bestellnummer,
MIN( his.`change_date` ) zahldatum
...
GROUP BY ord.`ordernumber`
MIN is an aggregate function so you can't use it in a JOIN straight up like you've tried above. You also are not comparing it to a value in your JOIN.
You'll want to do something like:
his.`change_date` = (SELECT MIN(his.`change_date`) FROM s_order_history where ord.`id` = his.`orderID`)
in your JOIN.

MySQL join same table twice on same column with different value returning most recent row only

I'm stuck trying to solve a small part of what is otherwise a complex JOIN.
We have an 'instructions' table and an 'estimates' table. In the 'estimates' we have multiple rows for different types of estimates for a given instruction.
Instructions Table
id | address | status
1 | 27 TAYLOR ROAD, ALBION PARK NSW 2527 | InProgress
Estimates Table
id | instruction_id | basis | basis_date | basis_value
1 | 1 | ContractPrice | 2012-04-05 | 124000
2 | 1 | CAMV | 2012-02-01 | 120000
3 | 1 | CustomerEstimate | 2012-06-07 | 132000
4 | 1 | ContractPrice | 2013-01-03 | 140000
5 | 1 | CustomerEstimate | 2013-02-09 | 145000
What we want is actually 2 joins of 'instructions' on 'estimates' based on instructions.id = estimates.instruction_id and estimates.basis for 1) the most recent 'CustomerEstimate' (aliasing basis_date and basis_value as estimate_date and estimate_value) and 2) most recent 'ContractPrice' (again, aliasing basis_date and basis_value as contact_date and contract_value).
The intended result would be as follows;
id | address | status | contract_price | contract_date | estimate_date | estimate_value
1 | 27 TAYLOR ROAD, ALBION PARK NSW 2527 | InProgress | 2013-01-03 | 140000 | 2013-02-09 | 145000
I would really appreciate some assistance from the SQL gurus out there.
Many thanks,
Trent.
Try
SELECT i.id,
i.address,
i.status,
p.max_date contract_date,
p.basis_value contract_price,
e.max_date estimate_date,
e.basis_value estimate_value
FROM Instructions i LEFT JOIN
(
SELECT q1.instruction_id, max_date, basis_value
FROM Estimates e JOIN
(
SELECT instruction_id, MAX(basis_date) max_date
FROM Estimates
WHERE basis = 'CustomerEstimate'
GROUP BY instruction_id
) q1 ON e.instruction_id = q1.instruction_id AND e.basis_date = q1.max_date
) e ON i.id = e.instruction_id LEFT JOIN
(
SELECT q2.instruction_id, max_date, basis_value
FROM Estimates e JOIN
(
SELECT instruction_id, MAX(basis_date) max_date
FROM Estimates
WHERE basis = 'ContractPrice'
GROUP BY instruction_id
) q2 ON e.instruction_id = q2.instruction_id AND e.basis_date = q2.max_date
) p ON i.id = p.instruction_id
Output:
| ID | ADDRESS | STATUS | CONTRACT_PRICE | CONTRACT_DATE | ESTIMATE_VALUE | ESTIMATE_DATE |
----------------------------------------------------------------------------------------------------------------------------
| 1 | 27 TAYLOR ROAD, ALBION PARK NSW 2527 | InProgress | 140000 | 2013-01-03 | 145000 | 2013-02-09 |
Here is SQLFiddle demo.
What is the contract_price here?
You can try the below
select inst.id
, inst.address
, inst.status
, est.basis_value as estimate_value
, est.basis_date as estimate_date
from instructions inst
, estimates est
where inst.id=est.instruction_id
and (est.basis='CustomerEstimate' or est.basis='ContractPrice')
order
by est.basis
, est.basis_date desc;