I have two tables, customers and Orders
Customers columns are
CustomerID,
Username,
Password,
Firstname,
Surname,
Email,
Mobile
Orders columns are
OrderID,
CustomerID,
Date,
Time,
Price,
Complete
I want to select all of the firstname and surnames from all the orders that have been complete. And yes It could be so that [0] = John Smith and [1] also = John Smith.
What I was thinking was
SELECT FirstName, Surname from order, customers
WHERE Complete = 'Yes' AND order.CustomerID = customer.CustomerID;
So first it looks at if the order is complete. If it is then it will look at the customer ID, then it will go to customers and get the firstname and surname of that customer then store it in the datatable.
Thank you for any help!!!
You could use EXISTS, the following query will return all customers that don't have incomplete (=0) orders:
select c.firstname, c.lastname
from customers c
where
not exists (select * from orders o
where c.customerid = o.orderid
and o.complete = 'No')
but it will also return customers that have no orders. If you want to exclude customers with no orders you could use an additional exist clause:
select c.firstname, c.lastname
from customers c
where
not exists (select * from orders o
where c.customerid = o.orderid
and o.complete = 'No')
and exists (select * from orders o where c.customerid = o.orderid)
or a group by clause:
select c.firstname, c.lastname
from customers c inner join orders o on c.customerid = o.customerid
group by c.customerid, c.firstname, c.lastname
having sum(o.complete='No') = 0
This will give you list of Firstname, Surname even though they don't have orders.
SELECT Customers.Firstname, Customer.Surname
FROM Customers, Orders
WHERE Orders.Complete = 'Yes'
LEFT JOIN Customers.CustomerID = Orders.CustomerID
I'd go with this personally:
SELECT c.Firstname, c.Surname FROM Customers c
INNER JOIN Orders o
ON c.CustomerID=o.CustomerID
WHERE o.Complete='Yes'
I like to be as explicit as possible with my queries, so anyone else who has to read my code understands the what, why and how. Though shouldn't you also select something to identify the order? Otherwise all you have is a list of names.
--Unique list of customer id, customer first name and customer surname.
SELECT DISTINCT
customers.customerid
, customers.firstname
, customers.surname
FROM orders
INNER JOIN customers
ON
customers.customerid = orders.customerid
AND orders.complete = 'Yes'
--Unique list of customer first name and customer surname, regardless
--if same names are tied to different customerid.
SELECT DISTINCT
customers.customerid
, customers.firstname
, customers.surname
FROM orders
INNER JOIN customers
ON
customers.customerid = orders.customerid
AND orders.complete = 'Yes'
Remove DISTINCT word if you want duplicates.
Related
There are two tables:
Customers:
ID
Name
Surname
City
Orders:
OrderId
CustomerId
Purchase
Price
I'm trying to find customer id,name,surname where he hasn't Purchase "Pizza".
Any help to fix my query? I tried with cp.Purchase != "Pizza" but doesn't work
SELECT DISTINCT ID,FirstName,LastName
FROM Customers c
INNER JOIN Orders cp ON c.ID = cp.OrderID
ORDER BY c.ID
WHERE cp.Purchase LIKE '%Pizza%'
try this
select * from Customers where Id not in (
select CustomerId From Orders WHERE cp.Purchase LIKE '%Pizza%'
)
The right query is
SELECT DISTINCT c.ID, c.Name, c.Surname
FROM Customers c JOIN Orders o on c.ID = o.CustomerID
WHERE c.ID <> ALL (
SELECT c2.ID
FROM Customers c2 JOIN Orders o2 on c.ID = o2.CustomerID
WHERE o2.Purchase = 'Pizza')
This is because you are looking for who never bought a pizza, so you will select data of customers which ID never appear (<> ALL) in orders table in a record where a pizza was bought.
By the way, check also SQL base, try understand before getting the answer.
I have these tables : customers, customer_invoices, customer_invoice_details, each customer has many invoices, and each invoice has many details.
The customer with the ID 574413 has these invoices :
select customer_invoices.customer_id,
customer_invoices.id,
customer_invoices.total_price
from customer_invoices
where customer_invoices.customer_id = 574413;
result :
customer_id invoice_id total_price
574413 662146 700.00
574413 662147 250.00
each invoice here has two details (or invoice lines) :
first invoice 662146:
select customer_invoice_details.id as detail_id,
customer_invoice_details.customer_invoice_id as invoice_id,
customer_invoice_details.total_price as detail_total_price
from customer_invoice_details
where customer_invoice_details.customer_invoice_id = 662146;
result :
detail_id invoice_id detail_total_price
722291 662146 500.00
722292 662146 200.00
second invoice 662147 :
select customer_invoice_details.id as detail_id,
customer_invoice_details.customer_invoice_id as invoice_id,
customer_invoice_details.total_price as detail_total_price
from customer_invoice_details
where customer_invoice_details.customer_invoice_id = 662147;
result :
detail_id invoice_id detail_total_price
722293 662147 100.00
722294 662147 150.00
I have a problem with this query :
select customers.id as customerID,
customers.last_name,
customers.first_name,
SUM(customer_invoices.total_price) as invoice_total,
SUM(customer_invoice_details.total_price) as details_total
from customers
join customer_invoices
on customer_invoices.customer_id = customers.id
join customer_invoice_details
on customer_invoice_details.customer_invoice_id = customer_invoices.id
where customer_id = 574413;
unexpected result :
customerID last_name first_name invoice_total details_total
574413 terry amine 1900.00 950.00
I need to have the SUM of the total_price of the invoices, and the SUM of the total_price of the details for each customer. In this case I'm supposed to get 950 as total_price for both columns (invoice_total& details_total) but it's not the case. what am I doing wrong & how can I get the correct result please. The answers in similar topics don't have the solution for this case.
When you mix normal columns with aggregate functions (for example SUM), you need to use GROUP BY where you list the normal columns from the SELECT.
The reason for the excessive amount in total_price for invoices is that the SUM is also calculated over each detail row as it is part of the join. Use this:
select c.id as customerID,
c.last_name,
c.first_name,
SUM(ci.total_price) as invoice_total,
SUM((select SUM(d.total_price)
from customer_invoice_details d
where d.customer_invoice_id = ci.id)) as 'detail_total_price'
from customers c
join customer_invoices ci on ci.customer_id = c.id
where c.id = 574413
group by c.id, c.last_name, c.first_name
db-fiddle
I used join against sub queries and then did a sum on the sums
SELECT c.id as customerID,
c.last_name,
c.first_name
SUM(i.sum) as invoice_total,
SUM(d.sum) AS details_total
FROM customers c
JOIN (SELECT id, customer_id, SUM(total_price) AS sum
FROM customer_invoices
GROUP BY id, customer_id) AS i ON i.customer_id = c.id
JOIN (SELECT customer_invoice_id as id, SUM(total_price) AS sum
FROM customer_invoice_details
GROUP BY customer_invoice_id) AS d ON d.id = i.id
WHERE c.id = 574413
GROUP BY c.id, c.name
The issue is in the joining logic. The table customers is used as the driving table in the joins. But in the second join, you are using a derivative key column from the first join, to join with the third tables. This is resulting in a Cartesian output doubling the records from the result from the nth-1 join, which is leading to customer_invoices.total_price getting repeated twice, hence the rolled up value of this field is doubled.
At a high level I feel that the purpose of rolling up the prices is already achieved in SUM(customer_invoice_details.total_price).
But if you have a specific project requirement that SUM(customer_invoices.total_price) should also be obtained and must match with SUM(customer_invoice_details.total_price), then you can do this:
In a separate query, Join customer_invoice_details and customer_invoices. Roll up the pricing fields, and have a result such that you have only one record for one customer ID.
Then use this as a sub-query and join it with the customers table.
You are aggregating along multiple dimensions. This is challenging. I would suggest doing the aggregation along each dimension independently:
select c.id as customerID, c.last_name, c.first_name,
ci.invoice_total,
cid.details_total
from customers c join
(select ci.sum(ci.total_price) as invoice_total
from customer_invoices ci
group by ci.customer_id
) ci
on ci.customer_id = c.id join
(select ci.sum(cid.total_price) as details_total
from customer_invoices ci join
customer_invoice_details cid
on cid.customer_invoice_id = ci.id
group by ci.customer_id
) cid
on cid.customer_id = c.id
where c.id = 574413;
A faster version (for one customer) uses correlated subqueries:
select c.id as customerID, c.last_name, c.first_name,
(select ci.customer_id, sum(ci.total_price) as invoice_total
from customer_invoices ci
where ci.customer_id = c.id
) as invoice_total,
(select ci.customer_id, sum(cid.total_price) as details_total
from customer_invoices ci join
customer_invoice_details cid
on cid.customer_invoice_id = ci.id
where ci.customer_id = c.id
) as details_total
from customers c
where c.id = 574413;
SELECT
ORDER_ITEM.OrderID,
ORDERS.OrderDate
FROM ORDER_ITEM LEFT JOIN ORDERS
ON ORDER_ITEM.OrderID = ORDERS.OrderID
LEFT JOIN PEOPLE
ON ORDERS.CustomerID = PEOPLE.PeopleId AND ORDERS.EmployeeID = PEOPLE.PeopleId
where PEOPLE.FirstName + PEOPLE.LastName = 'April Roberts'
My results are outputting 0 rows. Not sure what I am doing wrong here.
Make sure you have data in the table that match your criteria. e.g. You have orders by the person with the name April Roberts. If you use LEFT JOIN, the query will return all results despite if you do not have any order by the person. So, INNER JOIN or simply JOIN is fine if you ONLY want orders that associates with the person.
SELECT oi.OrderID, o.OrderDate
FROM ORDER_ITEM oi
JOIN ORDERS o ON oi.OrderID = o.OrderID
JOIN PEOPLE p ON o.CustomerID = p.PeopleId
WHERE p.FirstName = 'April' AND p.LastName = 'Roberts'
This should work better for the search (you are using a space that doesn't exist)
SELECT OI.OrderID, O.OrderDate
FROM ORDER_ITEM OI
LEFT JOIN ORDERS O ON OI.OrderID = O.OrderID
LEFT JOIN PEOPLE P ON O.CustomerID = P.PeopleId AND O.EmployeeID = P.PeopleId
WHERE P.FirstName='April' AND P.LastName = 'Roberts';
However, logically, CustomerID and EmployeeID can't match the same employee. You'd need a second link to people
SELECT OI.OrderID, O.OrderDate
FROM ORDER_ITEM OI
LEFT JOIN ORDERS O ON OI.OrderID = O.OrderID
LEFT JOIN PEOPLE P ON O.CustomerID = P.PeopleId
LEFT JOIN PEOPLE E ON O.EmployeeID = E.PeopleId
WHERE P.FirstName='April' AND P.LastName = 'Roberts';
Your error is that you want the people record match employee and customer of the same order, but the customer will never equal the employee of course.
Is April Roberts the customer or the employee? Decide and then select the data from the orders table for that customer or employee:
select orderid, orderdate
from orders
where customerid in
(
select peopleid
from people
where firstname = 'April'
and lastname = 'Roberts'
);
No need to join the order_item table. No need to join at all. Only join when you want joined data.
I am using IN for the case there exist two April Roberts. If there is a constraint on the table preventing that, then you can change IN to =.
If you were really interested in the orders linked to some April Roberts, not knowing whether she is employee or customer, you'd use EXISTS instead:
select orderid, orderdate
from orders o
where exists
(
select *
from people p
where p.firstname = 'April'
and p.lastname = 'Roberts'
and p.peopleid in (o.customerid, o.employeeid)
);
There is another error in your query by the way:
where PEOPLE.FirstName + PEOPLE.LastName = 'April Roberts'
You are adding two values here (+ is for numeric addition), so MySQL converts the strings FirstName and LastName to numbers. Such conversion from a string that starts with a letter results in the value zero in MySQL, so you have where 0 + 0 = 0 which is always true. If + would do string concatenation as you obviously supposed (which is the || operator in standard SQL and the CONCAT function in MySQL), then you'd probably have gotten where 'AprilRoberts' = 'April Roberts' which would always be false.
I have 2 tables:
Customers:
- ID
- NAME
Modulemembers:
- ID
- customer_id
- enabled
I use this to enable a function of my site for some customers.
I have a form where the admin of the site can add the module for a customer, so i need a query that looks for customers that are NOT member of the modulemembers table.
I made this:
SELECT customers.id,
customers.name
FROM customers,
modulemembers
WHERE customers_id != modulemembers.cust_id
ORDER BY customers.name
but it does not work. What am I doing wrong?
You can use NOT EXISTS in the WHERE clause to get the result:
SELECT c.id,
c.name
FROM customers c
WHERE not exists (select customer_id
from modulemembers m
where c.id = m.customer_id)
order by c.name
You can use a LEFT OUTER JOIN and filter based on NULLs. The query below will pull in all results from the customers table and the modulemembers table. If there is not a match in the modulemembers table then the custid will be NULL.
SELECT c.id, c.name
FROM customers c
LEFT OUTER JOIN modulemembers m ON c.customers_id = m.cust_id
WHERE m.custid IS NULL
ORDER BY c.name
Try something like this:
SELECT c.ID AS customerId,
c.NAME AS fullName,
m.ID AS memberId
FROM Customers AS c
LEFT JOIN Modulemembers AS m ON m.customer_id = c.ID
WHERE m.ID IS NULL;
I have 2 tables: Customers and Orders. A customer has many orders and an order belongs to a customer. The order can be approved (marked by a field approved_at).
I want to retrieve all the customers without any approved order. This includes customers without any order and customers with orders that aren't approved (approved_at = null).
Can I do this in a single query without subqueries?
SELECT ..., COUNT(Orders.id) AS cnt
FROM Customers
LEFT JOIN Orders ON (Customers.id = Orders.Customer_id) AND (Orders.approved_at is null)
HAVING cnt = 0
SELECT c.*
FROM Customers c
LEFT JOIN Orders o ON c.ID = o.CustomerID
WHERE o.ID IS NULL OR c.Approved_at IS NULL