How to group by twice or restrict a group by? - mysql

I have a location. A location has invoices. Invoices have fees. I want to get all the fees for a given month for a given location.
Here's what I can do:
SELECT
STR_TO_DATE(CONCAT_WS('-', YEAR(invoices.invoiceDate) , MONTH(invoices.invoiceDate), '01'), '%Y-%m-%d') as invoiceMonth,
AVG(fees.amount) as averageMonthlyInvoice,
SUM(fees.amount) as totalMonthlyInvoice
from invoices as invoices
inner join fees as fees
on fees.invoiceId = invoices.id
where invoices.locationId = 1
group by invoiceMonth
This second one would give me the average and total invoice information for an location. I want to be able to do this for all locations at once.
Here's what I want to do:
SELECT
invoices.locationId as locationId,
STR_TO_DATE(CONCAT_WS('-', YEAR(invoices.invoiceDate) , MONTH(invoices.invoiceDate), '01'), '%Y-%m-%d') as invoiceMonth,
AVG(fees.amount) as averageMonthlyInvoice,
SUM(fees.amount) as totalMonthlyInvoice
from invoices as invoices
inner join fees as fees
on fees.invoiceId = invoices.id
group by invoiceMonth, locationId
However, this last one would just average and total all invoices, not giving me the information for each specific location.

Perhaps using ORDER BY (conditions) might also help you get the data return you desire?

Related

mySQL - How can I see which users submitted orders last month but not this month?

I need to figure out the users who submitted orders last month but not this month. This is my current query to count total users, but how can I cross check to see who has bought this month but not the last?
SELECT DISTINCT(customer_user_id)
FROM customer_orders
WHERE created_on > '2020-07-01'
This is my the customer orders table
this would be the expected output, a list of all the users
EDIT: Additionally, I'm trying to get a report of the users who submitted orders in July but not August, with their amount total for the month, number of orders, and user cellphone #. This is the query I'm using but its not giving me the result.
SELECT DISTINCT(co.customer_user_id), SUM(co.amount), COUNT(co.order_id), s.cellphone
FROM customer_orders co
JOIN subscribers s
ON co.customer_user_id = s.user_id
WHERE co.created_on > '2020-07-01'
AND month(co.created_on) <> month(curdate());
This is my subscriber table, and above is my customer orders table.
As I understood you want to filter the user's which are again created in current month. So,
-- not sure if you really need distinct
SELECT DISTINCT(c.customer_user_id)
FROM customer_orders c
WHERE c.created_on > '2020-07-01'
AND month(c.created_on) <> month(curdate());

More than 1 rows returned from SELECT inside SELECT

I'm trying to create a query to find what is the total amount owed by each customer to the company. It is the GROUP BY customerNumber in the sub query that is creating the problem.
SELECT customerName,
customers.customerNumber,
SUM(quantityOrdered * priceEach) - ( SELECT SUM(amount) AS MoneyPayed FROM payments GROUP BY customerNumber ) AS AmountOwed
FROM payments
INNER JOIN customers ON payments.customerNumber = customers.customerNumber
INNER JOIN orders ON customers.customerNumber = orders.customerNumber
INNER JOIN orderdetails ON orders.orderNumber = orderdetails.orderNumber
GROUP BY customerNumber;
The tables I'm trying to link are payments and orderdetails.
When I get rid of the GROUP BY I get results in negatives as the total SUM of amount is subtracted from each row of SUM(quantityOrdered * priceEach).
How can I change this so that I can return multiple rows from payments to subtract from SUM(quantityOrdered * priceEach) from the order details table.
Link to DB as StackOverflow doesn't allow me to post images
Thanks for help, sorry if format is bad, this is my first post.
You will need a couple of subqueries to meet your requirement. Let us break it down.
First, you need the total value of orders from each customer. You're very close to the correct query for that. It should be
SELECT orders.customerNumber,
SUM(orderdetails.quantityOrdered * orderdetails.priceEach) owed
FROM orders
JOIN orderdetails ON orders.orderNumber = orderdetails.orderNumber
GROUP BY orders.customerNumber
This subquery's result set gives customerNumber and owed, the amount owed. Notice that orders::orderdetails is a one::many relationship, so we're sure we're counting each detail just once, so the SUMs will be correct.
Next we need the amount paid by each customer. This subquery is fairly simple.
SELECT customerNumber,
SUM(amount) paid
FROM payments
GROUP BY customerNumber
Now for the operation you're missing in your question: we need to join these two subqueries to your customers table.
SELECT customers.customerName, customers.customerNumber
owed.owed - paid.paid balance
FROM customers
LEFT JOIN (
SELECT orders.customerNumber,
SUM(orderdetails.quantityOrdered * orderdetails.priceEach) owed
FROM orders
JOIN orderdetails ON orders.orderNumber = orderdetails.orderNumber
GROUP BY orders.customerNumber
) paid ON customers.customerNumber = paid.customerNumber
LEFT JOIN (
SELECT customerNumber,
SUM(amount) paid
FROM payments
GROUP BY customerNumber
) owed ON customers.customerNumber = owed.customerNumber
See how this works? We join a table and two subqueries. Each subquery has either zero or one rows for each row in the table, so we need not use SUMs or GROUP BY in the outer query.
There's only one complication left: what if a customer has never paid anything? Then the value of paid.paid will be NULL after the LEFT JOIN operation. That will force the value of owed - paid to be NULL. So we need more smarts in the SELECT statement to yield correct sums.
SELECT customers.customerName, customers.customerNumber
COALESCE(owed.owed,0) - COALESCE(paid.paid,0) balance
...
COALESCE(a,b) is equivalent to if a is not null then a else b.
Pro tip In queries or subqueries with JOIN operations, always mention table.column instead of just column. The next person to work on your query will thank you.

SQL: Can I not use COUNT and AVG as aggregate functions when others are not agg?

Okay, next round.
Sorry, for not posting pictures of both code and output before. Still getting used to how StackOverflow works.
What I'm trying to get is the list of unique customers who started a certain month, the sum of their payments, a count of how many unique customers there are, and an average of their summed payments (total all customers payments divided by the number of customers for that month), grouped by unique customer id.
Can I do all that in the same query, or do I have to break that up into multiple queries? What other problems am I having? Feel free to pile on the problems? I need to know! thanks!
SELECT customer.customer_id AS Jancust_id,
SUM( payments.payment ) AS Jan_cust_pmts,
COUNT( DISTINCT customer.customer_id ) AS Jan_orig_cust,
AVG(payments.payment) as CustLifeRev
FROM telemon_payments_data payments
LEFT JOIN telemon_customer_data customer
ON payments.customer_id = customer.customer_id
WHERE DATE_FORMAT( customer.account_created_on, '%Y-%m' ) = '2016-01'
GROUP BY Jancust_id
I sense that you are trying to aggregate over customers, and hence you thought that specifying the customer_id in the GROUP BY clause was appropriate. Actually, the aggregate functions SUM() and COUNT() which you were using will implicitly aggregate over customers.
Try the following query:
SELECT SUM(payments.payment) AS Jan_cust_pmts,
COUNT(DISTINCT customer.customer_id) AS Jan_orig_cust
FROM telemon_payments_data payments
RIGHT JOIN telemon_customer_data customer
ON payments.customer_id = customer.customer_id
WHERE customer.account_created_on BETWEEN '2016-01-01' AND '2016-01-31'
As #LordBaconPants mentioned, in many databases you cannot use SUM() in this way without GROUP BY. In your case, grouping by month would be appropriate. We could rewrite your query as follows:
SELECT SUM(payments.payment) AS Jan_cust_pmts,
COUNT(DISTINCT customer.customer_id) AS Jan_orig_cust,
DATE_FORMAT(customer.account_created_on, '%Y-%m') AS year-month
FROM telemon_payments_data payments
RIGHT JOIN telemon_customer_data customer
ON payments.customer_id = customer.customer_id
WHERE DATE_FORMAT(customer.account_created_on, '%Y-%m') = '2016-01'
GROUP BY DATE_FORMAT(customer.account_created_on, '%Y-%m')
You can remove the WHERE clause from the above query to generate a monthly report.

mySQL How to find a name by max sum in different tables

I'm doing as a homework a bank database.
I have two tables: "Account" and "Transactions". Account holds name, surname and acc.number of a client. Transactions holds account number where money comes from, date (rrrr-mm-dd) and amount. I need to find a client with the biggest sum of transfered money in current month.
I tried
Account inner join (select acc_number, sum(Ammount) as Total from Transactions group by Acc.number order by Total) on Account.acc_number=Transactions.acc_number;
But it didn't work. Please help.
You are missing a "select fields" from your query.
I think this query should do what you're trying to achieve.
SELECT SUM(Ammount),Account.acc_number from Account
INNER JOIN Transactions ON Account.acc_number=Transactions.acc_number
WHERE MONTH(date) = MONTH(CURDATE()) AND YEAR(date) = YEAR(CURDATE())
GROUP BY Account.acc_number
ORDER BY SUM(Amount) DESC
LIMIT 1

MySQL query to get paid invoices

I have the following MySQL tables:
invoices
invoice_id,
invoice_number,
invoice_description,
invoice_value,
invoice_date
payments
payment_id
payment_invoice_id
payment_value
payment_date
My goal is to make a single query that can retrieve all the invoices that have been paid in full (the invoice_value must match the sum of payment_value).
Is it possible?
SELECT i.*
FROM Invoices i
JOIN Payments p ON i.invoice_id = p.payment_invoice_id
GROUP BY i.invoice_id
HAVING i.invoice_value = SUM(p.payment_value);
PS: Be sure you use NUMERIC(9,2) for currency data. Don't use FLOAT.