My question is simple. How can I compose a query in which I negate something? And I'm not refer to NOT condition. For example I have to select all the tourists that booked at least one pension(acc_type_code) whose rating is greater than 9, but did not book any 3 star hotel with a rating less than 9?
My tables:
Tourist
id (pk)
name
email
Booking
id_tourist (pk)
id_accomodation (pk)
Accomodation
id_accomodation (pk)
acc_type_code (fk)
nr_of_stars
rating
price
Accomodation type
acc_type_cde (pk)
acc_type_name
What I've tried:
SELECT t.id as id_tourist, t.name, t.email from Tourist t,
JOIN Booking b on (t.id = b.id_tourist)
JOIN Accomodation a on (b.id_accomodation = a.id_accomodation)
JOIN AccType at on (a.acc_type_code = at.acc_type_code)
WHERE a.rating > 9 AND .. ?
And here I'm blocked. Any suggestions?
You can use a LEFT OUTER JOIN
to locate the records you want to exclude from your query, and then filter them out in the WHERE
condition
SELECT t.id as id_tourist, t.name, t.email
FROM Tourist t
INNER JOIN Booking b on (t.id = b.id_tourist)
INNER JOIN Accomodation a on (b.id_accomodation = a.id_accomodation)
INNER JOIN AccType at on (a.acc_type_code = at.acc_type_code)
LEFT OUTER JOIN Accomodate a2 on (b.id_accomodation = a2.id_accomodation) AND a2.nr_of_stars = 3 AND a2.rating < 9
WHERE a.rating > 9 AND a2.id_accomodation IS NULL
NOTE: The above syntax assumes MSSQL is your SQL flavor.
based on further info from OP in comments, NOT EXISTS
would likely provide a simpler approach. The concept is similar: Locate the records you want to exclude, and wrap then in a NOT EXISTS
clause
SELECT t.id as id_tourist, t.name, t.email
FROM Tourist t
INNER JOIN Booking b on (t.id = b.id_tourist)
INNER JOIN Accomodation a on (b.id_accomodation = a.id_accomodation)
INNER JOIN AccType at on (a.acc_type_code = at.acc_type_code)
WHERE a.rating > 9
AND NOT EXISTS (
SELECT b2.id_tourist FROM Booking b2
INNER JOIN Accomodation a2 on (b2.id_accomodation = a2.id_accomodation)
WHERE a2.nr_of_stars = 3 AND a2.rating < 9
)
NOTE: You may need to add more joins inside the NOT EXISTS
clause to locate the records that should be excluded. I don't know your data.
should be easy as using a NOT EXISTS
SELECT t.id as id_tourist, t.name, t.email from Tourist t,
JOIN Booking b on (t.id = b.id_tourist)
JOIN Accomodation a on (b.id_accomodation = a.id_accomodation)
JOIN AccType at on (a.acc_type_code = at.acc_type_code)
WHERE a.rating > 9 AND
NOT EXISTS (
your query to get the same tourist_Id and has booked a 3 start hotel and under 9 ratings
)
Here is a LEFT JOIN
, anti-join method:
SELECT t.id as id_tourist, t.name, t.email
FROM Tourist t,
JOIN Booking b ON t.id = b.id_tourist
JOIN Accomodation a ON b.id_accomodation = a.id_accomodation
AND a.rating > 9
JOIN AccType at ON a.acc_type_code = at.acc_type_code
LEFT JOIN (SELECT t.id
FROM Tourist t
JOIN Booking b ON t.id = b.id_tourist
JOIN Accomodation a ON b.id_accomodation = a.id_accomodation
AND a.rating < 9
AND a.nr_of_stars = 3
) a2 ON a2.id = t.id
WHERE a2.id IS NULL
The outer query finds only tourists ( t.id
) that booked a hotel above a 9 rating. The inner query finds only tourists ( t.id
) that booked a 3 star hotel, below a 9 rating.
By doing a LEFT JOIN
between them, and limiting our results only to those that do not match ( WHERE a2.id IS NULL
) we are left with only those that booked a hotel above a 9 rating, and did not book a 3 star hotel with a rating below 9.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.