Querying a foreign key on a association table - mysql

Let's say i have the following model:
Customer(customer_id (PK), firstName, lastName, email)
Item(item_id (PK), name, description)
Orders(orders_id (PK), customer_id (FK), item_id (FK), promotion_id (FK)),
Promotion(promotion_id (PK), date, gift_id (FK))
Gift(gift_id (PK), name, description)
Now, let's say that i have the following requirement:
Retrieve the list of all orders (not grouped by) from all customers and the name column from both the item and gift associated.
The difficult part is that the association table orders has a foreign key column to a one to many table (promotion) that, in his turn, has the foreign key to the gift;
I have the following query that worked, but i figure out that should have a more elegant way to approach the problem than doing a lot of joins like this:
select concat(c.firstName, ' ', c.lastName) as customerName,
i.name, g.name
from customer as c
left join orders as o on c.customer_id = o.customer_id
inner join item as i on o.item_id = i.item_id
inner join promotion as p on o.promotion_id = p.promotion_id
inner join gift as g on p.gift_id = g.gift_id;
How i could resolve the query in a more elegant way?
Thanks in advance!

I think this is perfectly elegant. Joins are very classy and often misunderstood.

You can drop the INNER keywords as joins are inner by default, and the AS keywords are optional; also because your column names are the same across the joins, you can simply use USING instead of ON:
SELECT CONCAT_WS(' ', c.firstName, c.lastName) customerName,
i.name, g.name
FROM customer c
LEFT JOIN orders o USING (customer_id)
JOIN item i USING (item_id)
JOIN promotion p USING (promotion_id)
JOIN gift g USING (gift_id)
Indeed, if those are the only columns having the same name across the joined tables one could go further and use NATURAL joins (although I don't like that as it hides what's going on if the schema changes):
SELECT CONCAT_WS(' ', c.firstName, c.lastName) customerName,
i.name, g.name
FROM customer c
NATURAL LEFT JOIN orders o
NATURAL JOIN item i
NATURAL JOIN promotion p
NATURAL JOIN gift g

Related

Write a query to find the full names of customers who have rented sci-fi movies more than 5 times. Arrange these names in the alphabetical order

Hello below is my Code
DB: https://dev.mysql.com/doc/sakila/en/sakila-structure.html
select concat(first_name,' ',last_name) from
customer where customer_id in (
select customer_id from (
select customer_id, count(rental_id) as num
from
category
inner join film_category using(category_id)
inner join film using(film_id)
inner join inventory using(film_id)
inner join rental using (inventory_id)
where name='Sci-Fi'
group by customer_id, rental_id)
where num > 5)T)
when i am executing i am getting the below error
ERROR 1248 (42000) at line 2: Every derived table must have its own alias
Expected Outcome is "full names of customers who have rented sci-fi movies more than 5 times. Arrange these names in the alphabetical order"
Could you please let me know what is the mistake i am doing?
Welcome to SO!
First, it seems like you have 3 opening ( parens and 4 closing ) parens. You should delete the last parenthesis so you have balanced parens.
After that, you want to apply the alias to the deepest level query. (Similar question: What is the error “Every derived table must have its own alias” in MySQL?) You have...
where name='Sci-Fi'
group by customer_id, rental_id)
where num > 5)T)
You probably want...
where name='Sci-Fi'
group by customer_id, rental_id) AS T
where num > 5)
(Don't forget, there is no need for that extra closing paren, so you can see I removed it. It might be part of a bigger query you have, but it doesn't help the standalone code in the question.)
This will stop the immediate error that you're seeing. At least, now on my database, the error I see is: ERROR 1146 (42S02): Table 'db.customer' doesn't exist.
select concat(first_name, ' ', last_name) as Customer_name
from category
inner join film_category
using (category_id)
inner join film
using (film_id)
inner join inventory
using (film_id)
inner join rental
using (inventory_id)
inner join customer
using (customer_id)
where name = 'Sci-Fi'
group by Customer_name
having count(rental_id) > 3
order by Customer_name;
select concat(first_name,' ',last_name) as customer_name from customer
inner join rental
using(customer_id)
inner join inventory
using(inventory_id)
inner join film
using(film_id)
inner join film_category
using(film_id)
inner join category
using(category_id)
where name in ('sci-fi')
group by customer_name
having count(rental_id) > 2
order by customer_name

SQL join five tables

I am working on issue, and cannot resolve it.
I have five tables:
t_employee = {employee_id_pk, fullname, phone, position, passport}
t_facility = {facility_id_pk, direction, title}
t_employee_facility = {emp_fac_id_pk, employee_id_fk, facility_id_fk}
this table is #ManyToMany relationship
between 't_employee' and 't_facility'
t_transport = {transport_id_pk, type}
t_trip = {trip_id_pk, trip_code, employee_id_fk, transport_id_fk}
this table is #ManyToMany relationship between 't_employee' and 't_transport'
And I want to get unique rows
I tried something like this
SELECT
employee_id, fullname, passport, phone, position, direction, title,
trip_code
FROM
t_facility
INNER JOIN t_employee_facility USING (facility_id)
INNER JOIN t_employee USING (employee_id)
INNER JOIN t_trip USING (employee_id)
GROUP BY
employee_id,
facility_id,
trip_code
There are 8 uniquie rows.
But the above example gives me 18, when I remove trip_id I get 8 rows, but
in this case I get repeating trip_code values for each employee_id.
I want to extract only not repeating rows. I guess that, I should do it using INNER JOIN, but I'm not sure.
Is it possible to join all this tables ?
thank you
Regards
It can be achieved using nested join query as follow:
SELECT B.employee_id, employee_id, fullname, passport, phone,
position,direction, title, trip_code
FROM (SELECT A.employee_id, employee_id, fullname, passport, phone,
position,direction, title
FROM (SELECT employee_id, direction, title FROM t_facility
JOIN t_employee_facility
ON t_facility.facility_id = t_employee_facility.facility_id
) AS A
JOIN employee ON A.employee_id = employee.employee_id) AS B
JOIN t_trip ON B.employee_id = t_trip.employee_id;
the INNER JOIN keyword selects should have matching values in both tables.
Ex :
SELECT id_pk,information,about
FROM information
INNER JOIN employe ON information.id_pk= employe.id_employe;
So yes, you can join your table when declare it each table.
If you only want the rows to be unique but it is OK, that some employees show more than one facility or trip, you may use the DISTINCT keyword.
SELECT DISTINCT
employee_id,
fullname,
passport,
phone,
position,
direction,
title,
trip_code
FROM t_facility
INNER JOIN t_employee_facility
USING (facility_id)
INNER JOIN t_employee
USING (employee_id)
INNER JOIN t_trip
USING (employee_id);
There are many unclear things in your question, still I'm posting whatever I have figured-out.
First of all I cannot see the table t_employee in FROM clause so I'm not sure this query will work. To get the column values for fullname, passport, phone, position you need to add the relevant table t_employee into FROM clause.
I'm not pretty sure about the JOIN syntax, you can check the MySQL JOINs syntax here.
SELECT
employee_id, fullname, passport, phone, position, direction, title,
trip_code
FROM
t_employee
INNER JOIN t_facility USING (facility_id)
INNER JOIN t_employee_facility USING (facility_id)
INNER JOIN t_employee USING (employee_id)
INNER JOIN t_trip USING (employee_id)
GROUP BY
employee_id,
facility_id,
trip_code
If this still doesn't work, you can try doing SELECT DISTINCT to get unique records, see the syntax here.

Not a Unique table/alias- SQL

I'm getting the error " Not a Unique table/alias 'Customer' " when I run my join statement. I want to display all the information that I have. I've researched the JOIN statements and I can't find what's wrong.
SELECT Customer.CustomerID, Customer.FirstName, Customer.LastName, Customer.StreetAddress,Customer.City,Customer.State,Customer.Zipcode, Customer.HomePhone,Customer.MobilePhone,Customer.OtherPhone, Pizza.PizzaID,
Pizza.PizzaName, Pizza.Description, Pizza.UnitPrice, OrderInformation.OrderID, OrderInformation.OrderDate, OrderItem.Quantity
FROM Customer
JOIN OrderInformation ON OrderInformation.OrderID = OrderItem.OrderID
JOIN Pizza ON Pizza.PizzaID = OrderItem.PizzaID
JOIN Customer ON Customer.CustomerID = OrderInformation.CustomerID;
SELECT
...
FROM Customer
...
JOIN Customer
You're selecting FROM Customer and then doing JOIN Customer, meaning you now have two instances of Customer. When you reference something like Customer.CustomerID, your query doesn't know which iteration of the Customer table you're referring to.
If you actually needed two references to the same table, you could give one an alias. However, being that you reference an OrderItem table, but never JOIN or select FROM it, I have a hunch that one of those Customer tables should be OrderItem. Perhaps like this...
SELECT ...
FROM OrderItem
JOIN OrderInformation ON OrderInformation.OrderID = OrderItem.OrderID
JOIN Pizza ON Pizza.PizzaID = OrderItem.PizzaID
JOIN Customer ON Customer.CustomerID = OrderInformation.CustomerID;
I would strongly suggest that you use table aliases. It would appear that the first reference to Customer should really be OrderItem:
SELECT c.CustomerID, c.FirstName, c.LastName,
c.StreetAddress, c.City, c.State, c.Zipcode,
c.HomePhone, c.MobilePhone, c.OtherPhone,
p.PizzaID, p.PizzaName, p.Description, p.UnitPrice,
oinf.OrderID, oinf.OrderDate, oi.Quantity
FROM OrderItem oi JOIN
OrderInformation oinf
ON oinf.OrderID = oi.OrderID JOIN
Pizza p
ON p.PizzaID = oi.PizzaID JOIN
Customer c
ON c.CustomerID = oi.CustomerID;

Query for multiple tables

I'm trying understand how I can pull information from multiple tables at once in one query if that is possible.
I have 3 tables and I'm wondering if there is a way I can query all the product names for customers that live in california?
Table:
products
Fields:
productOid
productName
companyOid
Table:
customerData
Fields:
customerOid
firstName
lastName
state
Table:
orders
Fields:
orderNumber
customerOid
productOid
Would this fall under something like an INNER JOIN?
Also, I'm learning mySQL.
You will need to use inner joins for this.
SELECT DISTINCT p.productName
FROM orders o
INNER JOIN customerData c ON o.customerOid = c.customerOid
INNER JOIN products p ON o.productOid = p.productOid
WHERE c.state = 'CA';
I am using DISTINCT here because it's possible a customer would order the same product more than once (or multiple customers would order the same products) and I'm assuming you don't want duplicates.
I'm also making the assumption that your state is represented as a two character column.
Read more about joins
You could use one more join, but I would write it this way:
SELECT DISTINCT p.productName
FROM
orders o INNER JOIN products p
ON o.productOid = p.productOid
WHERE
o.customerOid IN (SELECT customerOid
FROM customerData
WHERE state = 'California')
It might be a little slover than a join, but it's more readable.
This shows products that CA customers have ordered:
SELECT p.productName
FROM orders o
INNER JOIN products p ON o.productOid = p.productOid
INNER JOIN customerData c ON o.customerOid = c.customerOid
WHERE c.state = 'CA'

Mysql + difference in two result sets

I have a pretty simple MySQL question. I have two tables, Customer and Orders. Customer table has fields (id, name) and Order has fields (id, customerID, and item).
I can find which customer bought product A and customers that bought product B with the following query in MySQL.
SELECT DISTINCT c.`id`, c.name, o.`item`, o.qty FROM `customer` as c
INNER JOIN order AS o ON (c.`Id` = o.`customerID`)
where o.`item` ="Product A"
Union
SELECT DISTINCT c.`id`, c.name, o.`item`, o.qty FROM `customer` as c
INNER JOIN order AS o ON (c.`Id` = o.`customerID`)
where o.`item` ="Product B"
How can find the difference and similarity in these two result sets?
1) I.e. Customers that bought only product A but did not by product B
2) I.e. Customers that bought both product A and B
Thank you for your assistance.
D
You can try using the LEFT OUTER JOIN to get the result.