Hi I have these 2 problems below and my attempt. Please give me some advice.
SQL database:
CUSTOMER table: CUST_ID, CUST_NAME, ...
PRODUCT table: PROD_ID, PROD_DESCRIPTION, ...
CUSTOMER_PRODUCTS table: CUST_ID and PROD_ID.
This database is used to track the products a customer owns, so CUSTOMER_PRODUCTS has an entry for each product a customer owns.
I want to:
A:
Write a SQL query that will return a list of all customers who do not own any products.
Here is my attempt:
SELECT CUSTOMER _PRODUCTS.CUST_ID, CUSTOMER.CUST_ID, CUSTOMER.CUST_NAME
FROM CUSTOMER
INNER JOIN CUSTOMER_PRODUCTS
ON CUSTOMER_PRODUCTS.CUST_ID != CUSTOMER.CUST_ID;
B:
Write a SQL query that will return a list of all customers who own a product with ‘SAW’ in the name.
Here is my attempt:
SELECT CUSTOMER _PRODUCTS.CUST_ID, CUSTOMER.CUST_ID, CUSTOMER.CUST_NAME
FROM CUSTOMER
INNER JOIN CUSTOMER_PRODUCTS
ON CUSTOMER_PRODUCTS.CUST_ID = CUSTOMER.CUST_ID and WHERE PROD_DESCRIPTION LIKE 'SAW';
What do you guys think? am I headed in the right direction?
For B
SELECT CUSTOMER _PRODUCTS.CUST_ID, CUSTOMER.CUST_ID, CUSTOMER.CUST_NAME
FROM CUSTOMER
INNER JOIN CUSTOMER_PRODUCTS ON CUSTOMER_PRODUCTS.CUST_ID = CUSTOMER.CUST_ID
and WHERE PROD_DESCRIPTION LIKE '%SAW%';
Other person beat me to part A
For the A, you may want to use LEFT JOIN and IS NULL:
SELECT CUSTOMER.CUST_NAME
FROM CUSTOMER
LEFT JOIN CUSTOMER_PRODUCTS ON CUSTOMER.CUST_ID = CUSTOMER_PRODUCTS.CUST_ID
WHERE CUSTOMER_PRODUCTS.CUST_ID IS NULL;
for the B, pease ask separate question, as it is separate.
Related
I have one table customer, and one bill, and one sell.
Customer table
id-----name
Bill table
id-----customer_id
Sell table
id-----customer_id-----bill_id-----qtt-----price
A customer can have the records in the sell table with customer_id, and also have the bill record in the bill table with customer_id and this bill record has record in the sell table with bill_id.
This means a customer can have direct or indirect (in this case by passing the bill table) with sell table.
Now how to join tables that retrieve the total sell of a customer with ascending or deciding order?
Any idea?
I have tried many ways for example something like below, but none of them was working:
SELECT
sell.id AS sell_id,
customer.id,
bill.id AS bill_id,
customer.`name`,
sell.quantity*sell.price AS sell_price
FROM
customer_tb customer
JOIN bill ON bill.customer_id = customer.id
JOIN sell ON sell.customer_id = customer.id OR sell.bill_id = bill.id
NOTE: In case of bill table has a record in the sell table, the customer_id column is NULL and also same for the customer sell record the bill_id is NULL, this means in the sell table in the same entry only one of the (customer_id, bill_id) column has value.
You have the customer column in your sell tables, you don't need to join with bill table.
SELECT
customer.id,
customer.name,
SUM(sell.quantity * sell.price) AS total_amount
FROM customer_tb as customer
INNER JOIN sell
On sell.customer_id = customer.id
GROUP BY customer.id
You have to group your rows by the customer to get their sum independently
Your challenge is to look up the correct Customer.name for each Sell row.
You need to join Sell to Customer, and also join Sell to Bill to Customer.
How to do this?
FROM Sell s
LEFT JOIN Cust c1 ON s.customer_id = c1.id
LEFT JOIN Bill b on s.bill_id = b.id
LEFT JOIN Cust c2 ON b.customer_id = c2.id
That gives us:
s.id: the Sale id
s.quantity, s.price: the business details of the Sale
c1.name: the Customer name directly from the Sale's customer_id
c2.name: the Customer name indirectly through the Sale's bill_id
Because we use LEFT JOINs, either name can be NULL depending on which ids are null. And, I believe you favor using the direct name over the indirect name if you have both.
That means we use COALESCE() to choose one name from the two. Something like this
SELECT s.id, s.Quantity, s.Price,
COALESCE (c1.name, c2.name) name,
COALESCE (c1.id, c2.id) customer_id
FROM Sell s
LEFT JOIN Cust c1 ON s.customer_id = c1.id
LEFT JOIN Bill b on s.bill_id = b.id
LEFT JOIN Cust c2 ON b.customer_id = c2.id
But, if you have a chance to rework this database before you put a ton of data into it, please consider redesigning things to get rid of this ambiguity. It's going to drive you mad and cost you bigger servers if you have to make it work well with megarows.
I have 3 tables:
Reservation, Trip, Customer
I only need to display the trip name, trip type, customer first name, customer last name of the customers who have multiple reservations
Sort of like this
Reservation table
Reservation_ID ... ... .. Customer_Num
16001 101
16002 101
16003 102
16004 103
16005 103
Customer table
Customer_ID ... ... .. Customer_Num
30 101
31 102
32 103
Customer table's primary ID is customer_ID and has a column name of
Customer_Num. this column name is also in the reservation table.
Reservation table's primary id is Reservation_ID
I’ve tried:
SELECT Customer.First_Name, Customer.Last_Name, Trip.Trip_Name, Trip.Type, Reservation.Customer_Num COUNT(Reservation.Customer_Num
FROM Reservation, Customer, Trip
WHERE Reservation.Customer_Num = Customer.Customer_Num
HAVING COUNT(Reservation.Customer_Num) > 1
GROUP BY Customer.First_Name, Customer.Last_Name, Trip.Trip_Name, Trip.Type, Reservation.Customer_Num;
Try this, presuming that Trip table using Customer_num field as foreign key
select A.Customer_id, A.Name, A.Last_name, B.name, B.type from Customer as A
where Customer_id in
(select Customer_Num from Reservation group by Customer_Num having count(Customer_Num) > 1)
left join Trip as B on Trip.Customer_Num = Customer.Customer_Num
You can use EXISTS :
SELECT t.*, c.*
FROM reservation r INNER JOIN
customer c
ON c.Customer_Num = r.Customer_Num INNER JOIN
trip t
ON . . .
WHERE EXISTS (SELECT 1
FROM reservation r1
WHERE r1.customer_no = r.customer_no AND
r1.Reservation_ID <> r.Reservation_ID
);
You need to adjust the ON clause for Trip table as you didn't specified the table information.
Presumming in your TRIP table you have columns as trip name, trip type, You may try below query -
SELECT Customer.First_Name
,Customer.Last_Name
,Trip.Trip_Name
,Trip.Type
,Reservation.Customer_Num
,COUNT(Reservation.Customer_Num) Customer_Num_Cnt
FROM Reservation R
INNER JOIN Customer C ON Reservation.Customer_Num = Customer.Customer_Num
INNER JOIN Trip T ON R.TRIP_ID = T.TRIP_ID
GROUP BY Customer.First_Name
,Customer.Last_Name
,Trip.Trip_Name
,Trip.Type
,Reservation.Customer_Num
-- HAVING COUNT(Reservation.Customer_Num) > 1;
If this doesn't fulfil your requirements, Please share the complete structure of TRIP table and CUSTOMER table.
This displays the results making it so I can pick which names have more than one reservation. In the reservation table it lists the customer num who has more than one reservation but I'm not sure why it wasn't working.
SELECT CUSTOMER.FIRST_NAME, CUSTOMER.LAST_NAME, TRIP.TRIP_NAME, TRIP.TYPE, RESERVATION.CUSTOMER_NUM, COUNT(RESERVATION.CUSTOMER_NUM) CUSTOMER_NUM_CNT
FROM RESERVATION
INNER JOIN CUSTOMER ON CUSTOMER.CUSTOMER_NUM = RESERVATION.CUSTOMER_NUM
INNER JOIN TRIP ON RESERVATION.TRIP_ID = TRIP.TRIP_ID
GROUP BY CUSTOMER.FIRST_NAME, CUSTOMER.LAST_NAME, TRIP.TRIP_NAME, TRIP.TYPE, RESERVATION.CUSTOMER_NUM
commented out--HAVING COUNT(RESERVATION.CUSTOMER_NUM) > 1;
Suppose that we have four tables in the following structure (Table name - fields):
person - id, name
doctor - id_person, specialty
pacient - id_person, disease
appointment - doctor_id, pacient_id, date
How can I construct a query to return the doctor's name and specialty, the pacient's name and disease and the appointment date?
Here's where I've got so far:
SELECT person.name, doctor.specialty, pacient.disease, appointment.date
FROM appointment
INNER JOIN person
ON appointment.pacient_id=person.id
INNER JOIN doctor
ON appointment.doctor_id=doctor.id_person
INNER JOIN pacient
ON appointment.pacient_id=pacient.id_person
But this is not returning the right fields. I think the problem resides in returning the same field (person.name) for two different ids (doctor and pacient) in the same row.
You need to do two separate joins to the person table, and use aliases to identify the individual tables like so:
select
dp.name as DoctorName
, doctor.specialty
, pp.name as PacientName
, pacient.disease
, appointment.date
from appointment
inner join doctor
on appointment.doctor_id = doctor.id_person
inner join person dp
on appointment.doctor_id = dp.id
inner join pacient
on appointment.pacient_id = pacient.id_person
inner join person pp
on appointment.pacient_id = pp.id
I'm looking to query 3 tables (Customers, Sales, & Top-Items) and create a list of the top-items that each customer has not purchased.
Relevant fields are
Customers: Customer#
Sales: Invoice#, Customer#, Item#
Top-Items: Item#
SELECT c.*, GROUP_CONCAT(t.`Item#`) AS list_of_top_items_not_purchased
FROM Customers c
CROSS JOIN `Top-Items` t
LEFT OUTER JOIN Sales s ON c.`Customer#` = s.`Customer#` AND s.`Item#` = t.`Item#`
WHERE s.`Item#` IS NULL
GROUP BY c.`Customer#`;
I've been struggling with this query.
I have two tables. One with coupons and Invoicenumbers. One with Invoicenumbers and customer names.
I need to get the customers who have not used a given coupon.
Here are the tables:
Promotion table:
Promotions
Invoice | Coupon
----------------
1 | couponA
2 | couponB
3 | couponB
Orders Table:
Orders
Invoice | Customer
------------------
1 | Jack
2 | Jack
3 | Jill
So Jack has used coupons A and B. And Jill has only used coupon B.
If my query were select customers who have not used coupon A, I should get Jill.
This works, but it seems clumsy and slow. Is there a better way?
SELECT Customer
FROM Promotions INNER JOIN Orders
ON Promotions.Invoice = Orders.Invoice
WHERE Customer NOT IN(
SELECT Customer
FROM Promotions INNER JOIN Orders
ON Promotions.Invoice = Orders.Invoice
WHERE Coupon = couponA)
GROUP BY Customer
Thanks for looking!
edit:
Here's an SQLFiddle schema
http://sqlfiddle.com/#!2/21d31/6
Updated: We should use prefer to use joins for better performance when its easy to do for us. Join vs. sub-query
Sql Fiddle
Select distinct Customer from orders o
join
(
SELECT distinct Customer as changedname FROM Orders o2
join
(
Select distinct invoice from Promotions where Coupon='couponA'
) t3
on o2.invoice = t3.invoice
) t2
on o.customer != t2.changedname;
Note: I changed column name customer for t3 because two joined tables must have different column names
Explanation:
Using inner or sub query is expensive when you have big data. use joins instead, lets learn converting subquery to join
With Subquery We had:
Select distinct Customer from orders where customer not in
(SELECT distinct Customer FROM Orders where invoice in
(Select distinct invoice from Promotions where Coupon='couponA'));
Converting sub-query to join
First step:
Select distinct Customer from orders o
join
(
SELECT distinct Customer as changedname FROM Orders where invoice in
(Select distinct invoice from Promotions where Coupon='couponA')
) t2
on o.customer != t2.changedname;
2nd step:
Select distinct Customer from orders o
join
(
SELECT distinct Customer as changedname FROM Orders o2 where invoice
join
(
Select distinct invoice from Promotions where Coupon='couponA'
) t3
on o2.invoice = t3.invoice
) t2
on o.customer != t2.changedname;
And that's it, much faster for tables having numerous rows
Original answer:
Use not in. Have a look.
Select distinct Customer from orders where customer not in
(SELECT distinct Customer FROM Orders where invoice in
(Select distinct invoice from Promotions where Coupon='couponA'));
Edit I have added distinct to make query faster
SQL Fiddle
SELECT DISTINCT o2.customer FROM ORDER o2
LEFT JOIN (promotions p1
JOIN Orders o1 ON p1.cuopon = 'CuoponA' AND p1.invoice = o1.invoice ) p3
ON o2.customer = p3.customer
WHERE p3.customer IS NULL
Try this query instead:
SELECT DISTINCT Customer
FROM Orders o1
WHERE NOT EXISTS (
SELECT 1
FROM Orders o2
INNER JOIN Promotions ON Promotions.Invoice = o2.Invoice
WHERE o1.Customer = o2.Customer AND Coupon = 'couponB')
The idea is to get rid of the GROUP BY by removing a join in the top part of the query, and also eliminate the NOT IN by making a coordinated subquery.
Here is a link to sqlfiddle.
Try this with a right join
SELECT Customer, Coupon
FROM Promotions
RIGHT JOIN Orders ON Promotions.Invoice = Orders.Invoice
AND Coupon = 'couponA'
GROUP BY Customer
HAVING Coupon IS NULL