Sql Min query condition with join - mysql

I'm having two tables
abserve_hotels
hotel_id name trendy
1 A 1
2 B 1
3 C 0
4 D 0
4 E 0
6 G 0
7 F 0
abserve_hotel_rooms
room_id room_prize hotel_id
1 235 1
2 500 2
3 1000 1
4 2356 7
5 800 7
Here, I'm using this following query
SELECT `h`.*,`ar`.* from `abserve_hotel_rooms` as `ar` JOIN `abserve_hotels` as `h` ON `ar`.`hotel_id` = `h`.`hotel_id` WHERE `h`.`trendy` =1 LIMIT 5
But,when I using this query will retrieve the hotel_id two times if it having two rooms in that hotel..
i.e.,
hotel_id name trendy room_id room_prize
1 A 1 1 235
1 A 1 3 1000
2 B 1 2 500
But,I need only the minimum of room_prize if the hotel_id having two rooms,
For example,
hotel_id name trendy room_id room_prize
1 A 1 1 235
2 B 1 2 500
Like this,Someone help me..

Use a MIN with GROUP BY will do.
SQLFiddle:
http://sqlfiddle.com/#!9/46ff3/1
SELECT `h`.*,`ar`.room_id, MIN(`ar`.room_prize) as min_room_prize
from `abserve_hotel_rooms` as `ar` JOIN `abserve_hotels` as `h` ON `ar`.`hotel_id` = `h`.`hotel_id`
WHERE `h`.`trendy` =1
group by h.hotel_id
LIMIT 5
SQLFiddle output:
hotel_id name trendy room_id min_room_prize
1 A 1 1 235
2 B 1 2 500

DROP TABLE IF EXISTS hotels;
CREATE TABLE hotels
(hotel_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,name CHAR(1) NOT NULL
,trendy TINYINT NOT NULL
);
INSERT INTO hotels VALUES
(1,'A',1),
(2,'B',1),
(3,'C',0),
(4,'D',0),
(5,'E',0),
(6,'G',0),
(7,'F',0);
DROP TABLE IF EXISTS rooms;
CREATE TABLE rooms
(room_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,room_prize INT NOT NULL
,hotel_id INT NOT NULL
);
INSERT INTO rooms VALUES
(1, 235,1),
(2, 500,2),
(3,1000,1),
(4,2356,7),
(5, 800,7);
SELECT h.*
, x.room_id
, x.room_prize
FROM hotels h
JOIN rooms x
ON x.hotel_id = h.hotel_id
JOIN
( SELECT hotel_id
, MIN(room_prize) room_prize
FROM rooms
GROUP
BY hotel_id
) y
ON y.hotel_id = x.hotel_id
AND y.room_prize = x.room_prize
WHERE h.trendy = 1
ORDER
BY h.hotel_id
LIMIT 5;
+----------+------+--------+---------+------------+
| hotel_id | name | trendy | room_id | room_prize |
+----------+------+--------+---------+------------+
| 1 | A | 1 | 1 | 235 |
| 2 | B | 1 | 2 | 500 |
+----------+------+--------+---------+------------+

Related

MySQL - find N prev and next entries given an ID and order clause

I have this structure
ID Value Price
1 a 10
2 b 30
3 c 30
4 d 20
5 e 5
6 f 40
I have a select to get list ordered by price
SELECT * FROM table ORDER BY Price ASC
which gives me
ID Value Price
5 e 5
1 a 10
4 d 20
2 b 30
3 c 30
6 f 40
Now on my web page, a user clicks on an item with ID=2 and wants some details about it. However, on this detail page, I want to show N previous and next items in order. How can I obtain N previous and next items, given the ID and ORDER BY clause?
drop table if exists mytable;
create table mytable (ID serial primary key, Value char(1), Price int);
insert into mytable values
(1,'a',10),
(2,'b',30),
(3,'c',30),
(4,'d',20),
(5,'e',5),
(6,'f',40);
select t2.id, t2.value, t2.price
from (
select id, row_number() over (order by price asc) as rownum
from mytable
) as t1
join (
select *, row_number() over (order by price asc) as rownum
from mytable
) as t2
on t2.rownum between t1.rownum-2 and t1.rownum+2
where t1.id = 2
order by price asc;
Output, tested on MySQL 8.0.29:
+----+-------+-------+
| id | value | price |
+----+-------+-------+
| 1 | a | 10 |
| 4 | d | 20 |
| 2 | b | 30 |
| 3 | c | 30 |
| 6 | f | 40 |
+----+-------+-------+

Select count for total times foreign key exists in table with join

My table setup is as follows
Shortlist
id (primary key)
property_id(foreign key)
user_id
1
100
2
2
101
2
3
103
4
4
100
1
5
100
3
6
101
1
Property
id (primary key)
account_id
100
1
101
2
102
3
103
4
I then have the following query
SELECT DISTINCT `s`.`user_id`, `s`.`property_id`, `p`.`id`, `p`.`account_number`, COUNT(`s`.`property_id`) as `shortlistCount`
FROM `shortlist` `s`
INNER JOIN `property` `p` ON s.`property_id` = p.`id`
WHERE s.`user_id` = "2"
GROUP BY s.`property_id`
LIMIT 10
I want to add a count field alias as shortlistCount that returns the total number of times each property_id field appears in the shortlist table. (or id field in the property table, whichever is easier in this context)
For example, the property_id of 100 appears 3 times in the shortlist table.
So the result should be
| user_id | property_id | id | account_number | shortlistCount |
|---------|-------------|-----|----------------|----------------|
| 2 | 100 | 100 | 1 | 3 |
| 2 | 101 | 101 | 2 | 2 |
However, shortlistCount currently always returns 1
How can I can update my shortlistCount alias to return the above result?
To count the property_ids you can use a correlated subquery:
SELECT s.user_id, s.property_id, p.id, p.account_number,
(select Count(*) from Shortlist s2 where s2.property_id = s.property_id) shortlistCount
FROM shortlist s
JOIN property p ON s.property_id = p.id
WHERE s.user_id = 2
LIMIT 10;

How do I update scores in table without using a ranking function

Table name is: result
ID Name score position
1 John 40 0
2. Ali 79 0
3 Ben 50 0
4 Joe 79 0
How can I update table result to give me the table below without using rank() as it does not support by server. Pls someone should help me with the MySQL code That breaks ties just as in table below.
ID Name score position
1 John 40 4
2. Ali 79 1
3 Ben 50 3
4 Joe 79 1
In MySQL prior to version 8 try using the multiple table update syntax:
UPDATE scores t
LEFT JOIN (
SELECT t1.id, COUNT(*) + 1 AS new_position
FROM scores t1
JOIN scores t2 ON t1.score < t2.score
GROUP BY t1.id
) agg ON t.id = agg.id
SET t.position = COALESCE(agg.new_position, 1)
fiddle
Lots of ways to skin this particular animal. How about...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(ID SERIAL PRIMARY KEY
,Name VARCHAR(12) NOT NULL
,score INT NOT NULL
);
INSERT INTO my_table VALUES
(1,'John',40),
(2,'Ali',79),
(3,'Ben',50),
(4,'Joe',79);
SELECT id
, name
, score
, FIND_IN_SET(score, scores) rank
FROM my_table
CROSS
JOIN
( SELECT GROUP_CONCAT(score ORDER BY score DESC) scores
FROM my_table
) scores
+----+------+-------+------+
| id | name | score | rank |
+----+------+-------+------+
| 1 | John | 40 | 4 |
| 2 | Ali | 79 | 1 |
| 3 | Ben | 50 | 3 |
| 4 | Joe | 79 | 1 |
+----+------+-------+------+
I've not provided an UPDATE, because you wouldn't normally store derived data.
You can use correlated sub-query as follows:
update your_table t
set t.position = (select count(*) + 1 from your_table tt
where tt.score > t.score)

MySQL join "connected" intervals

Lets say I have table
teach_subject(teacher_id, subject_id, min_grade_of_school, max_grade_of_school, color_in_timetable)
Example data:
teacher_id subject_id min_grade_of_school max_grade_of_school color_in_timetable
1 2 1 4 #A00
1 2 5 6 #0A0
1 2 9 11 #00A
1 3 1 7 #AA0
It is not allowed that min_grad_of_school > max_grad_of_school, but maybe they are equal.
It is also not allowed that for a given tuple (t_id_new, s_id_new, min_grade_new, max_grade_new, color_new) there exists an other tuple (t_id, s_id, min_grade, max_grade, color) in the table holding
t_id_new = t_id and s_id_new = s_id and
( min_grade <= min_grade_new <= max_grade or min_grade <= max_grade_new <= max_grade )
So for the given example a new tuple like (1,2,6,11,#FFF) or (1,2,2,7,#FFF) is not possible.
So far no problem.
Now I want to ignore the color and join the "connected" rows, i.e. if teacher 1 teaches subject 2 from the 1st grade to the 4th grade, and from the 5th grade to the 6th grade, you can also say he teaches subject 2 from 1st to 6th grade.
So I want to "join" the tuples (1,2,1,4) and (1,2,5,6) to (1,2,1,6) but i dont want to join (1,2,4,5) and (1,2,9,11), since ther is a (integer) gap between 5 and 9.
I just have no idea if there is a way to do this with MySQL. At the moment I just select all the data an edit the selected data with PHP. Is there a MySQL way to directly select what I want or should stick to PHP?
Edit
Example result (for the above example data) :
teacher_id subject_id min_grade_of_school max_grade_of_school color_in_timetable
1 2 1 6 #A00
1 2 9 11 #00A
1 3 1 7 #AA0
Edit 2
Maybe can use a stored procedure?
DROP TABLE IF EXISTS teach_subject;
CREATE TABLE teach_subject
(teacher_id INT NOT NULL
,subject_id INT NOT NULL
,min_g INT NOT NULL
,max_g INT NOT NULL
,color_in_timetable CHAR(4) NOT NULL
,PRIMARY KEY(teacher_id,subject_id,min_g)
);
INSERT INTO teach_subject VALUES
(1,2,1,4,'#A00'),
(1,2,5,6,'#0A0'),
(1,2,9,11,'#00A'),
(1,3,1, 7,'#AA0');
SELECT a.teacher_id
, a.subject_id
, a.min_g
, MIN(c.max_g) max_g
, a.color_in_timetable
FROM teach_subject a
LEFT
JOIN teach_subject b
ON b.teacher_id = a.teacher_id
AND b.subject_id = a.subject_id
AND b.min_g = a.max_g - 1
LEFT
JOIN teach_subject c
ON c.teacher_id = a.teacher_id
AND c.subject_id = a.subject_id
AND c.min_g >= a.min_g
LEFT
JOIN teach_subject d
ON d.teacher_id = a.teacher_id
AND d.subject_id = a.subject_id
AND d.min_g = c.max_g + 1
WHERE b.teacher_id IS NULL
AND c.teacher_id IS NOT NULL
AND d.teacher_id IS NULL
GROUP
BY a.teacher_id,a.subject_id,a.min_g;
+------------+------------+-------+-------+--------------------+
| teacher_id | subject_id | min_g | max_g | color_in_timetable |
+------------+------------+-------+-------+--------------------+
| 1 | 2 | 1 | 6 | #A00 |
| 1 | 2 | 9 | 11 | #00A |
| 1 | 3 | 1 | 7 | #AA0 |
+------------+------------+-------+-------+--------------------+

How to do an update on mysql database for increment values

I will give a small exemple for my problem.
I have two tables in my database.
"Car" with the rows: "id","name".
"Seats" with the rows: "cid","weight".
The weight for the seats referees to the order of the seats.A car can have from 0 to n seats.
My problem is that i have seats with the same weight on a car.
I need to do an update for every car where two or more seats have same weight.
CAR
--------------------------
id | name
--------------------------
1 | ford
--------------------------
SEATS
-------------------------------
cid | name | weight
-------------------------------
1 Seat1 | 7
1 Seat2 | 1
1 Seat3 | 7
1 Seat4 | 3
1 Seat5 | 2
1 Seat6 | 3
1 Seat N | N
-------------------------------
And i need to have:
CID is the CAR id
SEATS
-------------------------------
cid | name | weight
-------------------------------
1 Seat1 | 0
1 Seat2 | 1
1 Seat3 | 2
1 Seat4 | 3
1 Seat5 | 4
1 Seat6 | 5
1 Seat N | N
-------------------------------
The query will run on a very big database and will affect many rows, so it is need to be fast.
I have done the join on the tables, but i don`t know how to make the complete update method.
The INNER JOIN is needed for this.
You can use user-defined variables in order to achieve a serial no for your weight column
update t
join (
select `cid`, `name`,#rank:= #rank + 1 rank
from t join
(select #rank:=-1) t1
order by `cid`, `name`
) t2
using(`cid`, `name`)
set weight = t2.rank
Demo
or if you need to a serial weight no for each car group then you can do so
update t
join (
select `cid`, `name`,
#rank:=case when #group = cid
then #rank + 1
else 0 end rank,
#group:=cid
from t join
(select #rank:=-1,#group:= 0) t1
order by `cid`, `name`
) t2
using(`cid`, `name`)
set weight = t2.rank
Demo serial per group