Modify SQL query to get all users? - mysql

I currently have this query.
SELECT DISTINCT (o.customer_id), count( o.id ) AS orders, c.*
FROM `order` AS o LEFT JOIN customer AS c ON o.customer_id = c.id
GROUP BY customer_id
What it does is it returns all customers that have made an order and counts the number of orders each customer has made.
What I need to do is modify this query so it also returns those customers who haven't made an order. Do you have any idea how this would be done?
I tried to reverse the query but this didn't do the trick..
SELECT DISTINCT (o.customer_id), count( o.id ) AS orders, c.*
FROM customer AS c LEFT JOIN order AS o ON o.customer_id = c.id
GROUP BY o.customer_id

Try this.
SELECT o.customer_id, sum( case when o.id is not null then 1 else 0 end ) AS orders, c.*
FROM customer c
LEFT JOIN order o ON o.customer_id = c.id GROUP BY customer_id

What about:
SELECT DISTINCT (o.customer_id), count( o.id ) AS orders, c.*
FROM `order` AS o
LEFT OUTER JOIN customer AS c ON o.customer_id = c.id GROUP BY customer_id

SELECT o.customer_id, c.*
FROM customer AS c LEFT JOIN order AS o ON o.customer_id = c.id
WHERE o.id IS NULL
GROUP BY o.customer_id
You can also skip the "GROUP BY" clause because when the orders side is NULL, there is always only one row for the customer:
SELECT o.customer_id, c.*
FROM customer AS c LEFT JOIN order AS o ON o.customer_id = c.id
WHERE o.id IS NULL

Related

How do i sub query two joins?

I have created two queries that both return the required results independent of each other. I am trying to join them to have the returned values be customerName, Amount Ordered, and Amount Paid.
Currently, this query works but only returns the customerName. How can it get the query to return the other two columns?
SELECT c1.customerName
FROM
(SELECT cc.customerName, ROUND(SUM(od.priceEach * od.quantityOrdered), 2) as '$ Amount Ordered'
FROM customers cc
INNER JOIN orders o ON o.customerNumber = cc.customerNumber
INNER JOIN orderdetails od ON od.orderNumber = o.orderNumber
GROUP BY cc.customerName
) c1
INNER JOIN
(SELECT c.customerName, ROUND(SUM(p.amount), 2) as 'Total $ Amount Paid'
FROM customers c
INNER JOIN payments p ON p.customerNumber = c.customerNumber
GROUP BY c.customerName
) c2
WHERE c1.customerName = c2.customerName
GROUP BY c1.customerName
ORDER BY c1.customerName;
this should select the others column
SELECT c1.customerName, c1.Amount_Ordered as '$ Amount Ordered', c2.Total_Amount_Paid as 'Total $ Amount Paid'
FROM
(SELECT cc.customerName, ROUND(SUM(od.priceEach * od.quantityOrdered), 2) as Amount_Ordered
FROM customers cc
INNER JOIN orders o ON o.customerNumber = cc.customerNumber
INNER JOIN orderdetails od ON od.orderNumber = o.orderNumber
GROUP BY cc.customerName
) c1
INNER JOIN
(SELECT c.customerName, ROUND(SUM(p.amount), 2) as Total_Amount_Paid
FROM customers c
INNER JOIN payments p ON p.customerNumber = c.customerNumber
GROUP BY c.customerName
) c2
WHERE c1.customerName = c2.customerName
GROUP BY c1.customerName
ORDER BY c1.customerName;
simply add them to the select section:
SELECT c1.customerName, C1.amountOrdered, C2.amountPaid FROM ...
And one more word of advice - DONT use whitespace or special signs like $ in your column names, it is bad practice. I think it's a mistake that mySql even allows it

MySql query to select total orders for customers

There title does not quite describe well what i need from the query.
#sgeddes helped me come up with the following query but the query needs some alteration to accomplish my needs. I also modified the query slightly to not Select deleted customers but i couldn't change much due to the way this query is written is out my SQL knowledge.
SELECT d.customer_id,d.fname,d.lname,d.isactive,
o.lastdate,
Count(o2.order_id) AS 'total_orders'
FROM customers d
LEFT JOIN (SELECT MAX(order_id) order_id, customer_id
FROM orders
GROUP BY customer_id) m on d.customer_id = m.customer_id
LEFT JOIN orders o on m.order_id = o.order_id
LEFT JOIN orders o2 on d.customer_id = o2.customer_id
AND o2.balance > 0 AND o2.isActive > -1
WHERE d.user_id =945766 AND d.isActive > -1
AND o2.customer_id IS NULL
GROUP BY d.customer_id
I need the three following requirements.
count orders for customer with isActive > -1 (-1 = deleted)
Customers not in orders table (customer with no orders).
Customers with isActive = 0 and their corresponding order count
so briefly all I need is customer with isActive = 0 and to get an actual # for total_orders column.
In my attempt to better help you understand my requirement I created a SqlFiddle.
Please see my SqlFiddle
If your requirement is what you mentioned in your 3 points then you can use below queries-
If you want separate query then use below-
SELECT d.customer_id, d.fname, COUNT(o.order_id) AS Total_Orders
FROM customer d
LEFT JOIN orders o ON d.customer_id=o.customer_id
WHERE d.isActive > -1
GROUP BY d.customer_id;
SELECT DISTINCT d.customer_id, d.fname
FROM customer d
LEFT JOIN orders o ON d.customer_id=o.customer_id
WHERE o.customer_id IS NULL;
SELECT d.customer_id, d.fname, COUNT(o.order_id) AS Total_Orders
FROM customer d
LEFT JOIN orders o ON d.customer_id=o.customer_id
WHERE d.isActive = 0
GROUP BY d.customer_id;
If you want to merge them by union then use below-
SELECT 'isactive>-1' AS 'status', d.customer_id, d.fname, COUNT(o.order_id) AS Total_Orders
FROM customer d
LEFT JOIN orders o ON d.customer_id=o.customer_id
WHERE d.isActive > -1
GROUP BY d.customer_id
UNION ALL
SELECT DISTINCT 'Customer without Order' AS 'status', d.customer_id, d.fname, COUNT(o.order_id) AS Total_Orders
FROM customer d
LEFT JOIN orders o ON d.customer_id=o.customer_id
WHERE o.customer_id IS NULL
UNION ALL
SELECT 'isactive=0' AS 'status', d.customer_id, d.fname, COUNT(o.order_id) AS Total_Orders
FROM customer d
LEFT JOIN orders o ON d.customer_id=o.customer_id
WHERE d.isActive = 0
GROUP BY d.customer_id;
Note: Your main query is trying fetch latest order which can be for any other purpose, so if you provide your exact requirement if different from it then someone can help you.

Sums and subtotals in SELECT... HAVING result

I'm trying to get the sum of each customer's orders separately, but I'm actually getting the sum of all the orders. What am I doing wrong here?
SELECT c.customerNumber, sum( r.quantityOrdered * r.priceEach ) AS sum
FROM customers c, orders o, orderdetails r
WHERE c.customerNumber = o.customerNumber
AND o.orderNumber = r.orderNUmber
GROUP BY c.customerNumber
HAVING COUNT( o.orderNumber ) <=3
First, you should use JOIN as it is the standardised way of writing the syntax. Makes it easier to read.
SELECT c.customerNumber, sum( r.quantityOrdered * r.priceEach ) AS sum
FROM customers c
LEFT JOIN orders o ON c.customerNumber = o.customerNumber
LEFT JOIN orderdetails r ON o.orderNumber = r.orderNUmber
GROUP BY c.customerNumber
HAVING COUNT( o.orderNumber ) <=3
When you use LEFT JOIN, this will give the results of the table customers, even if they dont have any recods in the orders and orderdetails.
Give it a try!
Your query looks ok to me other than the HAVING clause. I don't know what you are really trying to achieve with HAVING COUNT( o.orderNumber ) <=3. Do you really want customers with order of 3 or less? Have you tried using :
SELECT c.customerNumber, sum(r.quantityOrdered * r.priceEach) AS sum
FROM customers c
INNER JOIN orders o ON c.customerNumber = o.customerNumber
INNER JOIN orderdetails r ON o.orderNumber = r.orderNUmber
GROUP BY c.customerNumber

Multiple inner joins to get a complex report, not working

For the schema below, I need to get this report
This is what I have
select c.name, sr.name, count(o.order_id)
from contact c
INNER JOIN accounts a
ON c.account_id=a.account_id
INNER JOIN sales_reps sr
ON a.sales_rep_id =sr.sales_rep_id
INNER JOIN orders o
ON a.account_id =o.account_id
where o.order_id in (
select SUM(oi.quantity*p.price) from
order_items oi INNER JOIN parts p
on oi.part_id =p.part_id
)
group by a.account_id, c.name
But this does not give any results.
Please help.
Your where condition is not right, how should be a order_id equal a sum?
Try the below:
select
c.name, sr.name, COUNT(o.order_id), SUM(op.order_total)
FROM
contact c
INNER JOIN
accounts a ON c.account_id = a.account_id
INNER JOIN
sales_reps sr ON a.sales_rep_id = sr.sales_rep_id
INNER JOIN
orders o ON a.account_id = o.account_id
INNER JOIN
(SELECT
oi.order_id, SUM(oi.quantity * p.price) AS order_total
FROM
order_items oi
INNER JOIN
parts p ON oi.part_id = p.part_id
GROUP BY
oi.order_id
) op ON o.order_id = op.order_id
WHERE o.delivery_data >= CURDATE()
GROUP by c.contact_id
It won't give results as your WHERE ... IN SELECT is based on a query returning a sum() value which will not equal a key (most likely), or incorrect at best... and since you are dealing with a quantity and price which will have decimal precision (typically), you won't even get that to match even LESS likely...
I would swap the query around to pre-qualify the orders within a given date in question and sum that... THEN join to rest...
select
c.name,
sr.name,
PreQualified.NumberOrders,
PreQualified.OrderTotal
from
( select
o.Account_ID,
count( distinct o.order_id ) as NumberOrders,
sum( oi.quantity * p.price ) as OrderTotal
from
orders o
join order_items oi
on o.order_id = oi.order_id
join parts p
on oi.part_id = p.part_id
where
o.Delivery_Date >= CURDATE()
group by
o.Account_ID ) as PreQualified
JOIN Accounts a
on PreQualified.Account_ID = a.Account_ID
Join Contact C
on a.Account_ID = c.Account_ID
JOIN Sales_Reps sr
ON a.sales_rep_id = sr.sales_rep_id
If you want to count records use
count(*)
Instead of
count(o.order_id)

MySQL - Query to return customer's first order

Basic schema (only relevant fields shown):
customers
id | fname | sname | email
orders
order_id | customer | level | timestamp
I need to select every customer, but along with their personal details I want to join the level of their first order.
SELECT c.fname, c.sname, c.email, o.level
FROM customers c
LEFT JOIN orders o ON c.id = o.customer
..?
Edit
I have tried two solutions so far and they completely kill my entire database. No database requests will complete after running the queries, so I'm wondering if maybe the queries are too large. There are about 10,000 orders and 15,000 customers. Is this expected? I've never had these problems before on these tables.
Well, this will work, but is not optimal:
SELECT c.fname, c.sname, c.email, o.level
FROM customers c
LEFT JOIN orders o ON c.id = o.customer
WHERE o.`timestamp` = ( SELECT MIN( o1.`timestamp` ) FROM orders o1 WHERE o1.customer = c.id )
GROUP BY c.id
Try this query -
SELECT c.fname, c.sname, c.email, o.level FROM customers c
LEFT JOIN (
SELECT o1.* FROM orders o1
JOIN (SELECT customer, MIN(timestamp) timestamp FROM orders GROUP BY customer) o2
ON o1.customer = o2.customer AND o1.timestamp = o2.timestamp) o
ON c.id = o.customer;
SELECT c.fname, c.sname, c.email, o.level
FROM customers c
LEFT JOIN orders o ON c.id = o.customer
ORDER BY o.timestamp ASC LIMIT 1
SELECT c.fname, c.sname, c.email, o.level
FROM customers c
LEFT JOIN orders o ON c.id = o.customer
ORDER BY o.timestamp
GROUP BY c.id
Subselects are definitely not the most efficient but here's a query
SELECT c.fname, c.sname, c.email, o.level,
(select level from orders
where c.id = o.customer order by timestamp asc limit 0,1) as level
FROM customers c
This will give you ALL customers (orders or not) and their corresponding level. If you performance is slow, make sure you have proper indexes too