SQL Query related to average and length - mysql

i have a question. im currently doing an assignment, and having trouble in one particular request.
the request is:
Find Customers who have purchased more than 2 times. Get the
1. customer information
2. purchase frequency
3. total spending
4. avg basket size.
i already got 1 - 3, but i cant do much about number 4.
the values on product can have several values, separated by commas.
~> (product id: 12,4,5) -> if an order buys more than 1 product
i got to the point where i can separate it with length replace, but im a bit confused on how to show it to the average basket size.
thanks for any help!
SQL Table Image
sql table
**Customer**
Customer ID
Name
AddressCity
**Order**
OrderID
CustomerID
ProductID
Total
**Delivery**
DeliveryID
OrderID
AddressCity
this is my current sql statement
SELECT Customer.*, Order.CustomerID,
COUNT(Order.CustomerID) AS PurchaseFrequency,
SUM(Order.Total) AS TotalSpending
FROM Customer JOIN Order
ON Customer.CustomerID=Order.CustomerID
Group By Customer.CustomerID
Having Count(*) > 1

LEN(Order.ProductID) - LEN(REPLACE(Order.ProductID, ',', '')) + 1
Should give you the total amount of products per order.
Just add that to your existing statement.
SELECT Customer.*, Order.CustomerID,
COUNT(Order.CustomerID) AS PurchaseFrequency,
SUM(Order.Total) AS TotalSpending,
AVG(LEN(Order.ProductID) - LEN(REPLACE(Order.ProductID, ',', '')) + 1) as AvgProdQuantityPerOrder
FROM Customer JOIN Order
ON Customer.CustomerID=Order.CustomerID
Group By Customer.CustomerID
Having Count(*) > 1
EDIT:
The fields used in the SELECT part should also be specified in the GROUP BY part. Your query becomes then something like this:
SELECT Customer.CustomerID, Customer.Name, Customer.AdressCity,
COUNT(Order.CustomerID) AS PurchaseFrequency,
SUM(Order.Total) AS TotalSpending,
AVG(LEN(Order.ProductID) - LEN(REPLACE(Order.ProductID, ',', '')) + 1) as AvgProdQuantityPerOrder
FROM Customer JOIN
Order ON Customer.CustomerID=Order.CustomerID
GROUP BY Customer.CustomerID, Customer.Name, Customer.AdressCity
Having Count(*) > 1

Related

Explain SQL "SELECT count(*) FROM t AS 2 WHERE t1.col1 = t2.col1"

Can anyone, please, explain syntax of following request? The question is - if test2 is a result of count function, it is just a number. How can it be treated as a table (revenue.country_code = test2.country_code)? This code works, but I don't understand how. Thanks a lot for any answer.
SELECT customer_user_id, revenue, country_code FROM revenue
WHERE
(SELECT count(*)
FROM revenue AS test2
WHERE revenue.country_code = test2.country_code
AND test2.revenue > revenue.revenue) < 5
and media_source = 'facebook'
ORDER BY country_code, revenue DESC;
This is called a Correlated Subquery. The Subquery contains a reference to the table in the main query in its WHERE clause and it works similar to a join.
What this is saying in english is "We compare the number of records in this table for this country_id that have a higher revenue than this record's revenue. If that count is less than 5, then keep this record".
If it helps to understand, this could also be written with window functions:
SELECT *
FROM
(
SELECT customer_user_id, revenue, country_code
,DENSE_RANK() OVER (PARTITION BY country_code ORDER BY revenue DESC) as revenuerank
FROM revenue
WHERE media_source = 'facebook'
) sub
WHERE sub.revenuerank < 5

why UNION ALL command in mysql doesn't give back any results?

I am trying to merge two queries into one, but UNION is not working for me.
Here is the code:
SELECT
Customer_A,
Activity,
Customer_P,
Purchase
FROM (
SELECT
buyer_id as Customer_A,
COUNT(buyer_id) As Activity
FROM
customer_info_mxs
GROUP BY buyer_id
UNION ALL
SELECT
buyer_id as Customer_P,
SUM(purchase_amount) As Purchase
FROM
customer_info_mxs
GROUP BY buyer_id
)sub
I expect to have 4 columns as a result, but I get 2 instead (Customer_A) and(Activity).
If the query is supposed to return a list of customers, their number of purchases, and the total amount they’ve spent, then you can use a single query like this:
SELECT mxs.buyer_id as Customer,
COUNT(mxs.purchase_id) As Activity,
SUM(mxs.purchase_amount) As Purchases
FROM customer_info_mxs mxs
GROUP BY mxs.buyer_id;
Otherwise, your first subquery will always be a buyer_id and a value of 1.
Be sure to change purchase_id to whatever the unique id is for each purchase if you wish to see that number.
I think there is some confusion about the union statement. The union statement returns a row set that is the sum of all of the 'unioned' queries; since these queries have only 2 columns, the combined output only has two columns. The fact that the columns have different names is irrelevant. The column names in the output are being applied from the first query of the union.
One option is to just do
select buyer_id, count(buyer_id), sum(purchase_amount) from customer_info_mxs group by buyer_id
From your question, it looks like you are trying to do a pivot, turning some of the rows into additional columns. That could be done with ... some difficulty.
i read your comment,
'main goal is to creat a dataset in which returns 5 columns as: Customer_A, Activity (top 100), customer_P, Purchase(top 100), inner join of activity and purchase'
please try this query
SET #row_number = 0, #row_number2 = 0;
SELECT t1.Customer_A,t1.Activity, t2.Customer_P, t2.Purchase
from (
SELECT (#row_number:=#row_number + 1) AS n, t.Customer_a, t.Activity
from (
select buyer_id as Customer_A,COUNT(buyer_id) As Activity
FROM customer_info_mxs
GROUP BY buyer_id
order by Activity desc
Limit 100
)t
) t1
left join (
SELECT (#row_number2:=#row_number2 + 1) AS n,
FROM (
select buyer_id as Customer_P, SUM(purchase_amount) Purchase
FROM customer_info_mxs
GROUP BY buyer_id
order by Purchase desc
Limit 100
)t
) t2 on t2.n=t1.n
basic idea is, i just create some temporary number 0-99 to table 1 (t1) and join to temporary number on table 2 (t2)

MYSQL - SUM of a column based on common value in other column

I'm stuck on crafting a MySQL query to solve a problem. I'm trying to iterate through a list of "sales" where I'm trying to sort the Customer IDs listed by their total accumulated spend.
|Customer ID| Purchase price|
10 |1000
10 |1010
20 |2111
42 |9954
10 |9871
42 |6121
How would I iterate through the table where I sum up purchase price where the customer ID is the same?
Expecting a result like:
Customer ID|Purchase Total
10 |11881
20 |2111
42 |16075
I got to: select Customer ID, sum(PurchasePrice) as PurchaseTotal from sales where CustomerID=(select distinct(CustomerID) from sales) order by PurchaseTotal asc;
But it's not working because it doesn't iterate through the CustomerIDs, it just wants the single result value...
You need to GROUP BY your customer id:
SELECT CustomerID, SUM(PurchasePrice) AS PurchaseTotal
FROM sales
GROUP BY CustomerID;
Select CustomerID, sum(PurchasePrice) as PurchaseTotal FROM sales GROUP BY CustomerID ORDER BY PurchaseTotal ASC;
Just by having a little Google search, I managed to find a page doing exactly what you're doing (I think). I have tailored the query below to fit your circumstance.
SELECT CustomerID, SUM(PurchasePrice) AS PurchaseTotal
FROM sales
GROUP BY CustomerID
ORDER BY PurchaseTotal ASC
Link to Page with Tutorial on SQL Groups

Swap Values from database after performing count

I know I can do a count from mysql by doing this:
Select customer, Count (customer) Numbers from TblOrders group by customer
I want to count how many times each customer appears in the Order table.
After that I want to update Order table by swapping the customer id of the customer with the highest number of orders with another customer with id = 1.
Customer | Numbers
1 | 5
2 | 18
3 | 0
so here the highest was C2 so it'll swap C1 with C2 now after performing another count, I should get the table below.
Customer | Numbers
1 | 18
2 | 5
3 | 0
I also know the swapping can be done this way from a little research I've done.
Update TblOrders Set Customer = Case when 1 then 2
when 2 then 1
end
where TblOrders in (1, 2)
the problem with this statement is that it assumes I already know the two ID's that I'm swapping. but in case I don't know but I want the second one to be the ID with the highest number of orders...how do I go about it?
You want to issue an UPDATE request which affects all rows that belong to either one of the two customers in question. So the basic idea is this:
UPDATE TblOrders
SET customer = IF(customer == 'C1', #MaxCust, 'C1')
WHERE customer IN ('C1', #MaxCust)
If your customer IDs were integers, you could abbreviate this to
UPDATE TblOrders
SET customer = 1 + #MaxCust - customer
WHERE customer IN (1, #MaxCust)
This works because a + b - a = b and a + b - b = a, so a and b are exchanged.
My notation above was using a user variable #MaxCust to store the ID of the customer to be swapped. Depending on your environment, you might also use application code to enter the correct value into the query. Using a user variable, you could set it like this:
SELECT customer
FROM TblOrders GROUP BY customer
ORDER BY COUNT(*) DESC
LIMIT 1
INTO #MaxCust
after taking a look at # MvG's solutions, I came up with my own solution which is below.
SELECT customer FROM TblOrders GROUP BY customer ORDER BY COUNT(*) DESC LIMIT 1 INTO #MaxCust;
Update TblOrders Set Customer = Case
when 1 then #MaxCust
when #MaxCust then 1
end
where TblOrders in (1, #MaxCust );

MySQL query for weighted voting - how to calculate with values assigned to different columns

I have a voting application that writes values to a mysql db table. It is a preference/weighted voting system so people choose a first option, second option, and third option. These all go into separate fields in the table. I'm looking for a way to write a query that will assign numerical values to the responses (3 for a first response, 2 for a second, 1 for a first) and then display the value with the summed score. I've been able to do this for total number of votes
select count(name) as votes,name
from (select 1st_option as name from votes
union all
select 2nd_option from votes
union all
select 3rd_option from votes) as tbl
group by name
having count(name) > 0
order by 1 desc;
but haven't quite figured out how to assign values to response in each column and then pull them together. Any help is much appreciated. Thanks!
You could do something like this:
select sum(score) as votes,name
from (select 1st_option as name, 3 as score from votes
union all
select 2nd_option as name, 2 as score from votes
union all
select 3rd_option as name, 1 as score from votes) as tbl
group by name;