MySQL: Find the average balance of customers based on State - mysql

Find the average balance of customers based on State
select * from Customer_info;
select * from Account_info;
select Customer_info.Customer_ID, Customer_info.State, Account_info.Balance, Account_info.Customer_ID
from Customer_info
inner join Account_info on Customer_info.Customer_ID = Account_info.Customer_ID;
select Customer_info.Customer_ID, Customer_info.State, avg(Balance) as Average_Bal
from Customer_info
inner join Account_info on Customer_info.Customer_ID = Account_info.Customer_ID
group by State;
Stuck, could use some help/suggestions.

You seem to want:
select c.state, avg(a.balance) as average_bal
from customer_info c
inner join account_info a on a.customer_id = c.customer_id
group by c.state;
The select clause needs to be consistent with the group by clause: all non-aggregated column must appear in the group by clause.
Note that I added table aliases, which shortens the query. I also prefixed column balance with the table it belongs to, so the query is unambiguous (I assumed account_info).

Related

Get the sum of MySQL query result

I have a table BILLS with ID_CONTRACT_INST, F_SUM, DT_EVENT(Date) Columns
And another table CONTRACTS with ID_CONTRACT_INST(primary key), V_EXIT_IDENT
My TASK: sum of F_SUM column from table BILLS where
V_EXIT_IDENT from Table CONTRACTS = 1158
I get: All but the sum
select BILLS.ID_CONTRACT_INST, BILLS.F_SUM
from BILLS
where ID_CONTRACT_INST IN
(select ID_CONTRACT_INST from CONTRACTS
where V_EXIT_IDENT = 1158);
If BILLS.ID_CONTRACT_INST is unique then use
select BILLS.ID_CONTRACT_INST, SUM(BILLS.F_SUM) F_SUM
from BILLS
where ID_CONTRACT_INST IN (select ID_CONTRACT_INST
from CONTRACTS
where V_EXIT_IDENT = 1158)
GROUP BY BILLS.ID_CONTRACT_INST WITH ROLLUP;
In the output you will see additional row with BILLS.ID_CONTRACT_INST value of NULL and total sum in F_SUM column.
GROUP BY Modifiers
This appears to simply need:
select sum(BILLS.F_SUM)
from CONTRACTS
left join BILLS using (ID_CONTRACT_INST)
where V_EXIT_IDENT = 1158
Unless you meant separate sums for each contract, which is:
select CONTRACTS.ID_CONTRACT_INST, sum(BILLS.F_SUM)
from CONTRACTS
left join BILLS using (ID_CONTRACT_INST)
where V_EXIT_IDENT = 1158
group by CONTRACTS.ID_CONTRACT_INST
Note that if you only want to include results for contracts that have at least one bill, you would use inner join instead of left join. (In the case of the first query, this would return no result rows instead of a zero if there were no bills found for any selected contract.)
You need to apply the sum function on the values to be aggregated and group them by all your output table's unaggregated columns.
select BILLS.ID_CONTRACT_INST, sum(BILLS.F_SUM)
from BILLS
where ID_CONTRACT_INST IN
(select ID_CONTRACT_INST from CONTRACTS
where V_EXIT_IDENT = 1158)
group by BILLS.ID_CONTRACT_INST;
Alternatively, a left join works the same way:
select BILLS.ID_CONTRACT_INST, sum(BILLS.F_SUM)
from BILLS as b
left join CONTRACTS as c
ON b.ID_CONTRACT_INST = c.ID_CONTRACT_INST
where V_EXIT_IDENT = 1158
group by BILLS.ID_CONTRACT_INST;

subquery shows more that one row group by

I am trying to get the data for the best 5 customers in a railway reservation system. To get that, I tried getting the max value by summing up their fare every time they make a reservation. Here is the code.
SELECT c. firstName, c.lastName,MAX(r.totalFare) as Fare
FROM customer c, Reservation r, books b
WHERE r.resID = b.resID
AND c.username = b.username
AND r.totalfare < (SELECT sum(r1.totalfare) Revenue
from Reservation r1, for_res f1, customer c1,books b1
where r1.resID = f1.resID
and c1.username = b1.username
and r1.resID = b1.resID
group by c1.username
)
GROUP BY c.firstName, c.lastName, r.totalfare
ORDER BY r.totalfare desc
LIMIT 5;
this throws the error:[21000][1242] Subquery returns more than 1 row
If I remove the group by from the subquery the result is:(its a tabular form)
Jade,Smith,1450
Jade,Smith,725
Jade,Smith,25.5
Monica,Geller,20.1
Rach,Jones,10.53
But that's not what I want, as you can see, I want to add the name 'Jade' with the total fare.
I just don't see the point for the subquery. It seems like you can get the result you want with a sum()
select c.firstname, c.lastname, sum(totalfare) as totalfare
from customer c
inner join books b on b.username = c.username
inner join reservation r on r.resid = b.resid
group by c.username
order by totalfare desc
limit 5
This sums all reservations of each client, and use that information to sort the resulstet. This guarantees one row per customer.
The query assumes that username is the primary key of table customer. If that's not the case, you need to add columns firstname and lastname to the group by clause.
Note that this uses standard joins (with the inner join ... on keywords) rather than old-school, implicit joins (with commas in the from clause: these are legacy syntax, that should not be used in new code.

Combine two SELECT queries with different function

I have one table for reports. My first select query is that combines all sales tables
SELECT *, ds_sales.id_sales
FROM ds_sales LEFT JOIN
ds_payment
ON ds_sales.id_sales=ds_payment.id_sales LEFT JOIN
customer_info
ON ds_payment.id_customer=customer_info.id_customer INNER JOIN
ds_salesdetails
ON ds_salesdetails.id_sales=ds_sales.id_sales
WHERE customer_info.id_customer = '".$_POST["id_customer"]."'
This is the result of the query
and my second query is this, to filter the same sales serial number, since the ds_salesdetails table have many sales serial number
select ds_salesdetails.id_sales, count(*),
group_concat(ds_salesdetails.id_product)
from ds_salesdetails
having count(*) >= 1
I need to merge them to create a report for customers sales.
Join with the grouped subquery instead of the whole table.
SELECT *, ds_sales.id_sales
FROM ds_sales LEFT JOIN
ds_payment
ON ds_sales.id_sales=ds_payment.id_sales LEFT JOIN
customer_info
ON ds_payment.id_customer=customer_info.id_customer LEFT JOIN
(SELECT id_sales, count(*) as product_count,
group_concat(ds_salesdetails.id_product) AS product_list
from ds_salesdetails
GROUP BY id_sales) AS grouped ON grouped.id_sales = ds_sales.id_sales
WHERE customer_info.id_customer = '".$_POST["id_customer"]."'

MySQL - Group orders count by clients numbers

I want to group order's count to show how many clients have that number of orders.
I have come up with:
select count(*) as quantidade_pedidos, clientes.id
from pedidos
inner join clientes
on pedidos.cliente_id = clientes.id
where pedidos.aprovado = 1
group by quantidade_pedidos
but I just can't group by 'quantidade_pedidos' anyway.
Is there any way to group by a temporary column? Another way of doing this? show how many clients (number) have that number of orders placed?
Example
8 orders placed -> 3 clients have 8 orders placed
etc
Your original query is wrong. You need to group by clientes.id:
select count(*) as quantidade_pedidos, c.id
from pedidos p inner join
clientes c
on p.cliente_id = c.id
where p.aprovado = 1
group by c.id;
In an aggregation query, the unaggregated columns go in the group by, not the aggregated ones.
Also note that table aliases make the query easier to write and to read.
As for the question in the first line, use a subquery:
select quantidade_pedidos, count(*)
from (select count(*) as quantidade_pedidos, c.id
from pedidos p inner join
clientes c
on p.cliente_id = c.id
where p.aprovado = 1
group by c.id
) x
group by quantidade_pedidos;
But given that the query in the question doesn't work, I'm not sure this is what you really want to do.

SQL retrieving filtered value in subquery

in this cust_id is a foreign key and ords returns the number of orders for every customers
SELECT cust_name, (
SELECT COUNT(*)
FROM Orders
WHERE Orders.cust_id = Customers.cust_id
) AS ords
FROM Customers
The output is correct but i want to filter it to retrieve only the customers with less than a given amount of orders, i don't know how to filter the subquery ords, i tried WHERE ords < 2 at the end of the code but it doesn't work and i've tried adding AND COUNT(*)<2 after the cust_id comparison but it doesn't work. I am using MySQL
Use the HAVING clause (and use a join instead of a subquery).....
SELECT Customers.cust_id, Customers.cust_name, COUNT(*) ords
FROM Orders, Customers
WHERE Orders.cust_id = Customers.cust_id
GROUP BY 1,2
HAVING COUNT(*)<2
If you want to include people with zero orders you change the join to an outer join.
There is no need for a correlated subquery here, because it calculates the value for each row which doesn't give a "good" performance. A better approach would be to use a regular query with joins, group by and having clause to apply your condition to groups.
Since your condition is to return only customers that have less than 2 orders, left join instead of inner join would be appropriate. It would return customers that have no orders as well (with 0 count).
select
cust_name, count(*)
from
customers c
left join orders o on c.cust_id = o.cust_id
group by cust_name
having count(*) < 2