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
Related
I currently am trying to write a query that shows customers with at least 5 orders and customer with no orders. Orders are tracked in their own table and in order to find customers with 0 orders we have to find the customers NOT IN orders. Below is my query I'm trying to use and it returns the same customer 5 times for zero orders.
with t1 as
(select o.customerNumber, c.customerName, count(o.orderNumber) as FiveOrders
from orders o join customers c on (o.customerNumber = c.customerNumber)
group by o.customerNumber having count(o.orderNumber) = 5),
t2 as
(select distinct o.customerNumber, c.customerName, count(o.orderNumber) as NoOrders
from orders o join customers c on (o.customerNumber = c.customerNumber)
group by c.customerNumber not in(select customerNumber from orders))
select distinct t1.customerNumber as FiveOrderNumber, t1.customerName as FiveOrderName,
t2.customerNumber as NoOrderNumber, t2.customerName as NoOrderName
from t1 join t2
order by NoOrderName;
Any and all help is appreciated thanks!
If the errors were only in the second table to, I think it is after using
having with condition NOT IN without any logical comparison, I think you can get wanted results easily like:
select distinct customerNumber, customerName, "0" as NoOrders
from customers
where customerNumber not in (Select customerNumber from orders)
If the group by is important, you can use it like in your code.
Zero or five could be counted together with LEFT JOIN
select c.customerNumber, max(c.customerName) customerName, count(o.orderNumber) as FiveOrdersOrZero
from customers c
left join orders o on o.customerNumber = c.customerNumber
group by c.customerNumber
having count(o.orderNumber) in ( 0, 5 )
order by FiveOrdersOrZero
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 two different queries that each do half the job I need. how to combine them.
orders table has orderNumber and customerNumber, customers table has customerNumber and salesRepEmployeeNumber, orderdetails has multiple lines of the same orderNumber each showing price&quantity of different items).
(counting the number of orders from different customers each sales rep has)
select c.salesRepEmployeeNumber, count(*)
from customers c
inner join orders o1
on c.customerNumber = o1.customerNumber
group by c.salesRepEmployeeNumber;
and
(counting the revenue made by each sales rep)
select c.salesRepEmployeeNumber, sum(o2.priceEach*o2.quantityOrdered) as "Revenue"
from customers c
inner join orders o1
on c.customerNumber = o1.customerNumber
inner join orderdetails o2
on o1.orderNumber = o2.orderNumber
group by c.salesRepEmployeeNumber;
I need a query to know the employee number, # of orders, and revenue. I tried
select sum(o2.priceEach*o2.quantityOrdered) as "Revenue", c.salesRepEmployeeNumber, count(*)
from customers c
inner join orders o1
on c.customerNumber = o1.customerNumber
inner join orderdetails o2
on o1.orderNumber = o2.orderNumber
group by c.salesRepEmployeeNumber;
but it returns the count of items/products from the orders (e.g. 1 order has three products)
SELECT salesRepEmployeeNumber,
t1.`count(*)` AS `count`,
t2.Revenue
FROM (complete text of 1st query) AS t1
LEFT JOIN (complete text of 2nd query) AS t2 USING (salesRepEmployeeNumber)
complete text means "without final semicolon".
If your data guarantees that the amount of rows produced by 2nd query is equal to one produced by 1st query then you may use not LEFT but INNER joining.
Also test
select c.salesRepEmployeeNumber
, COUNT(DISTINCT o1.id) AS orders_count
, sum(o2.priceEach*o2.quantityOrdered) as "Revenue"
from customers c
join orders o1
on c.customerNumber = o1.customerNumber
join orderdetails o2
on o1.orderNumber = o2.orderNumber
group
by c.salesRepEmployeeNumber;
where o1.id is primary key expression (or any unique non-NULL column/expression/index) of orders table.
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.
I can find the total number of customers with at least 5 orders using an SQL COUNT with subquery:
SELECT COUNT(*) FROM (
SELECT c.id FROM customers as c
INNER JOIN orders as o ON c.id = o.customer_id
GROUP BY c.id
HAVING COUNT(o.id) >= 5
) as temp
However I'd like to know how to achieve the same thing using the Rails active record query interface, if possible.
I have the code:
total_count = Customer.joins("INNER JOIN orders ON customers.id = orders.customer_id").group("customers.id").having("COUNT(orders.id) >= 5").count
But that results in a hash map of the customer id and number of orders, because the SQL that is generated looks like:
SELECT COUNT(*) AS count_all, customers.id AS customers_id FROM `customers` INNER JOIN orders ON customers.id = orders.customer_id GROUP BY customers.id HAVING COUNT(orders.id) >= 5
Is there another way to achieve what I'm aiming for using Rails conventions? Or should I just build the raw query?
You would need to join if you wanted some other info from customers, like their names or something like that. If count is all that you want just do a simple query on orders table:
SELECT * FROM orders
GROUP BY customer_id
HAVING COUNT(customer_id) >= 5
and count rows in the result set.