MySQL innerjoin 3 tables - mysql

Supposing I had 3 tables
Passenger (Id [pk], name)
Airplane (registration [pk], num_seats)
Booking (Id, passenger_id [fk -> Passenger.Id], airplane_registration [fk -> Airplane.registration])
The booking table would be a junction object here as there is a many to many relationship between tables Passenger and Booking.
How could I select all the details related to a particular booking id (say 'abcde')?
Is this correct:
SELECT Passenger.name, Airplane.num_seats, Booking.Id
FROM Booking
JOIN Passenger ON Passenger.Id = Booking.passenger_Id
JOIN Airplane ON Booking.airplane_registration = Airplane.registration
WHERE Booking.Id = 'abcde';
Is this the right way to do it?
Also, If I wanted to select all bookings and their details, would I do it the same way? (Without the where clause)?
I was looking to find out if this was correct for a test as MySQL has gone down on my machine.

Yes, your query would work for getting the details of the passengers and the flight for the particular booking ID. For getting all bookings, I would add an ORDER BY bookingID and if needed by passenger name and flight registration.

Without knowing your schema, there's no way to be sure, but that looks just fine to me.

Related

How to get all records from two tables where doesn't exists in third

I'm looking to find a way to display a list of users that have cancelled a booking today.
The way my system works when a user cancels a booking is by adding a record into a cancellations table and deleting the record from the bookings table.
Currently I have
select distinct
members.firstname, members.lastname, cancelations.time, cancelations.groupnumber
from
members inner join cancelations on members.memberid = cancelations.memberid
where
cancelations.date = "CURRENT_DATE"
This works perfectly fine, except, this will also show if a user moves their appointment to a later/earlier time as the system will cancel then re-book.
So i believe what I would need is something like:
select distinct column names from tables where cancelations.date = "CURRENT_DATE" AND where the user hasn't got any records in the bookings table today
Tables in use (simplified)
Members - memberid, firstname, lastname
Cancelations - cancelationid, memberid, date, time, groupnumber
bookings - bookingid, memberid,date,time,groupnumber
So use NOT EXISTS() which is exactly what you are asking for :
select distinct members.firstname, members.lastname, cancelations.time, cancelations.groupnumber
from members
inner join cancelations
on members.memberid = cancelations.memberid
where cancelations.date = "CURRENT_DATE"
AND NOT EXISTS(SELECT 1 FROM bookings b
WHERE DATE(b.dateField) = DATE(cancelations.date)
AND b.memberid = member.memberid)
This checks that a record in the same day for the same member doesn't exists in booking table
I would go about this by changing your table structure for the bookings table. Instead of storing the state of a cancellation across multiple tables, I would just add a new column to bookings called isActive. This column will be set to 1 when a booking is created and will be set to 0 when one is deleted. Also when a booking is restored, it will be set to 1. This is a common technique known as "soft" deletion. It allows you to logically delete a record without actually removing it or moving it to another table. At some later point, you can archive stale deleted bookings to another table.
Here is the table structure:
CREATE TABLE bookings (`id` int PRIMARY KEY,
`memberid` int,
`isActive` tinyint
`date` datetime);
Now the query to find out if the user does not have any bookings from today is sane and straightforward:
SELECT COUNT(*)
FROM bookings
WHERE memberid = 1 AND
date = CURDATE() AND
isActive = 1
The query given by #sagi looks promising, but when you find yourself writing complex queries to answer simple business questions it might pay to think about the architecture.

how to design: users with different roles see different records

I have a schema design question for my application, hope I can get advices from teachers. This is very alike of Role Based Access Controll, but a bit different in detail.
Spec:
For one company, there are 4 roles: Company (Boss) / Department (Manager) / Team (Leader) / Member (Sales), and there are about 1 million Customers records. Each customer record can be owned by someone, and he could be Boss or Manager or Leader or Sales. If the record's owner is some Sales, then his upper grade (say: his leader / manager / boss) can see this record as well (but others: say the same level of his workmates, cannot see, unless his upper grade manager share the customer to his workmates), but if the record's owner is boss, none except the boss himself can see it.
My Design is like this (I want to improve it to make it more simple and clear):
Table:
departments:
id (P.K. deparment id)
d_name (department name)
p_id (parent department id)
employees
id (P.K. employee id)
e_name (employee name)
employee_roles
id (P.K.)
e_id (employee id)
d_id (department id)
customers
id (P.K. customer id)
c_name (customer name)
c_phone (customer phone)
permissions
id (P.K.)
c_id (customer id)
e_id (owner employee id)
d_id (this customer belongs to which deparment)
share_to (this customer share to other's id)
P.S.: each employee can have multi roles, for example, employee A can be the manager of department_I and meanwhile he can also be one sales of deparment_II >> Team_X.
So, when an employee login to application, by querying from employee_roles table, we can get all of the department ids and sub department ids, and save them into an array.
Then I can use this array to query from permissions table and join it with customers table to get all the customers this employee should see. The SQL might look like this:
SELECT * FROM customers AS a INNER JOIN permissions AS b ON a.id =
b.c_id AND (b.d_id IN ${DEP_ARRAY} OR e_id = ${LOGIN_EMPLOYEE_ID} OR
share_to = ${LOGIN_EMPLOYEE_ID})
I don't really like the above SQL, especially the "IN" clause, since I am afraid it will slow down the query, since there are about 1 million records or even more in the customer table; and, there will be as many records as the customers table in the permissions table, the INNER JOIN might be very slow too. (So what I care about is the performance like everyone :))
To my best knowledge, this is the best design I can work out, could you teachers please help to give me some advice on this question? If you need anything more info, please let me know.
Any advice would be appreciated!
Thanks a million in advance!!
Do not use an array, use a table, ie the value of a select statement. And stop worrying about performance until you know more basics about thinking in terms of tables and queries.
The point of the relational model is that if you structure your data as tables then you can looplessly describe the output table and the DBMS figures out how to calculate it. See this. Do not think about "joining"; think about describing the result. Whatever the DBMS ends up doing is its business not yours. Only after you become knowledgeable about variations in descriptions and options for descriptions will you have basic knowledge to learn about performance.

Dynamically structured mySQL database for an Airline Reservation App

I am working on a personal project and needed some guidance with a mySQL database. I am trying to simulate an airlines reservation system where a user has a personal account added to an Accounts db table (with username and password information). Then I have my Flights db table to store all of the available flights. The Flights db table has all of the flights with information (columns) on departure city, arrival city, departure time, arrival time, price, available seats, and seat capacity.
My question is:
When a user books a flight I must update the available seat value (int) in the Flights table. But then I also must add the flight to the user's account in the Accounts table. I am wondering how to handle this in mySQL, do I have to add a new column to the Accounts table with the corresponding flight's table index from the Flight's db table. Then continue adding a booked flight column as a user books flights to keep track of all the flights a user has booked? Is there a better way to update the Accounts table with flights booked information?
All help is very much appreciated.
Honestly, I would probably go about this a little differently. You may think about adding an additional table that tracks seat reservations. Something like:
TABLE: Accounts
ID | First Name | Last Name | Username | Password
TABLE: Flights
ID | DepartureCity | ArrivalCity | DepartureTime | Price | SeatingCapcity
TABLE: Reservations
ID | Account_ID | Flight_ID | SeatNumber
You can then use SQL functions and math to determine the number of seats available on a particular flight and maintain just the Reservations table when making updates. This also links all flights a particular account is associated with and is not "hard coded" to a particular column. (ie: A user can reserve more than one flight)
The best way to achieve this is to introduce a new table Bookings. A possible structure might be
CREATE TABLE Bookings (user_id INTEGER NOT NULL, flight_id INTEGER NOT NULL);
Then you can fetch all flights of a given user by
SELECT f.* FROM Users u
LEFT JOIN Bookings b ON u.id = b.user_id
LEFT JOIN Flights f ON b.flight_id = f.id
WHERE u.id = ?
And count the bookings for a given flight by
SELECT count(*) FROM Flights f
LEFT JOIN Bookings b
WHERE f.id = ?
This structure has several advantages:
You don't have to change the schema if users book more and more flights. Changing the schema of your database is a quite complex an expensive operation. (BTW: There is a maximum column count in MySQL)
You have an point where you can add further fields that are concerned with bookings. Maybe you want to track reservations.
Its more natural to fetch and add data. If you add columns booked_flight_1 booked_flight_2 and so on. You have to check which slot isn't already taken, which gets more and more complex when you consider deletions. Here it as easy as running this
INSERT INTO Bookings (user_id, flight_id) VALUES (1, 2)
If have to check if a given flight is available, it might be better to check this using your program and insert the booking into the database, if it is.
Joins and transactions might be the techniques you will find useful. The MySQL documentation and every good book on relational databases will give you an introduction in this. Your question sounds to me, as a classical instructional example.

In MySQL, how do I do an insert based on a join condition?

Thanks for looking!
Background
I have virtually no experience with the LAMP stack, but I have recently started an online store that uses OpenCart which is based on the LAMP stack.
The store allows for me to assign reward points to customers and I am giving each new customer 10 points just for creating an account.
Unfortunately, the OpenCart admin GUI only allows me to do this manually, one user at a time.
I do, however, have access to an interface that will allow me to run MySql commands and I would like to solve the problem using this approach.
Within the database created by OpenCart, I have a oc_customer table which contains all of my customers, and then I have a oc_customer_reward table which keys off of the customer id and assigns a new record each time a customer is awarded points. Here is what that looks like:
Question
How do I write a MySql query that will see if a customer from oc_customer does NOT exist in the oc_customer_reward table and IF THEY DO NOT EXIST, then create a record in the oc_customer_reward table (worth 10 points) for that customer?
I am not asking for working code (unless you really want to provide it) and I am willing to do the work myself, but frankly I don't know where to start. What would be the approach?
UPDATE
Per Olaf's suggestion, I am able to get all customers NOT in the oc_customer_reward table with his suggested query:
SELECT customer_id
FROM oc_customer
WHERE customer_id NOT
IN (
SELECT customer_id
FROM oc_customer_reward
)
Now, I just need to iterate the results of that query (sorry I am not a database guy!) and insert a row in oc_customer_reward for each of them. Kind of like a foreach loop in C#. Any thoughts?
First find customers not in the reward table:
select customer_id from oc_customer
where customer_id not in (select customer_id from oc_customer_reward);
then take that and insert an entry into the reward table:
insert into oc_customer_reward (customer_id, points)
select customer_id, 10 from oc_customer
where customer_id not in (select customer_id from oc_customer_reward);
This is not tested, but I hope it helps for a start.
Not tested and unsure about the table structure of oc_customer but following query should help you
INSERT INTO oc_customer_reward ( customer_id, description, points, date_added )
SELECT customer_id, 'reward for registration', 10, CURRENT_TIMESTAMP FROM oc_customer WHERE NOT EXISTS ( SELECT * FROM oc_customer_reward r WHERE r.customer_id = oc_customer.customer_id );
More details about the EXISTS statement you can find here
http://dev.mysql.com/doc/refman/5.5/en//exists-and-not-exists-subqueries.html

Retrieving specific tuples using Mysql

I have some problems retrieving specific tuples.
I am actually a student trying to build a Room management system. I have two tables:
Room(roomID,hotelname,rate)
and
Reservation(resID,arriveDate,departDate,roomID).
I am not sure how to retrieve the rooms that are available between 2 specific dates.
This was the query that i used.
SELECT Room.roomID,hotelname,rate
FROM Room
LEFT JOIN Reservation
on ( Room.roomID=Reservation.resID
and arriveDate >='2010-02-16'
and departDate <='2010-02-20'
)
GROUP BY roomID,hotelname,rate
HAVING count(*)=0;'
but it returns an empty set. Can any1 be kind enough to tell me what mistake i am doing??
I guess Room.roomID=Reservation.resID should be Room.roomID=Reservation.roomID.
You could try a different approach with a subselect:
SELECT roomID,hotelname,rate
FROM Room
WHERE roomID NOT IN (SELECT roomID FROM Reservation WHERE arriveDate >='2010-02-16' and departDate <='2010-02-20')