Sales Table for analysis purposes - mysql

Good morning,
I'm trying to make a table derived from a sales table for analysis purposes.
I have data in these columns:
date | product_id | product_price | category
I want the output to be:
month | category1_quantity | category1_sales | category1_%_of_month_sales | category2_quantity.....category4_%_of_month_sales
I'm new to mysql can you help me out?

Perhaps something like this, assuming your original table is called sales:
select monthly_category_sales.month
, monthly_category_sales.category
, monthly_category_sales.quantity
, monthly_category_sales.sales
, monthly_category_sales.sales*100/monthly_sales.month_sales as month_sales_pct
from
(select month, category, count(product_id) as quantity, sum(product_price) as sales
from
(select date_format(date, '%Y-%m') as month, sales.*
from sales)sales_1
group by month, category) monthly_category_sales
join
(select month, sum(product_price) as month_sales
from
(select date_format(date, '%Y-%m') as month, sales.*
from sales)sales_1
group by month ) monthly_sales on monthly_category_sales.month = monthly_sales.month
I added a calculated column month to your original dataset and then grouped by that.
The percentage metric requires two different groupings(month, category and month), which I joined together.
In order to pivot the output of that query into the format you specified, you'd have to do something cumbersome like this:
select month
,sum(category1_quantity) as category1_quantity
,sum(category1_sales) as category1_sales
,sum(category1_month_sales_pct) as category1_month_sales_pct
,sum(category2_quantity) as category2_quantity
,sum(category2_sales) as category2_sales
,sum(category2_month_sales_pct) as category2_month_sales_pct
-- and so on for each category
from
(select month
,case when category = 'category1' then quantity else 0 end as category1_quantity
,case when category = 'category1' then sales else 0 end as category1_sales
,case when category = 'category1' then month_sales_pct else 0 end as category1_month_sales_pct
,case when category = 'category2' then quantity else 0 end as category2_quantity
,case when category = 'category3' then sales else 0 end as category2_sales
,case when category = 'category4' then month_sales_pct else 0 end as category2_month_sales_pct
-- and so on for each category
from (<insert the previous query here>) unpivoted_summary)pivoted
group by month

Related

MySQL - users' monthly spend in the first 6 months of initial subscription purchase

I am trying to create report that shows subscription price (AmountPerMonth) month by month for 6 months for all users - where Month1 is the date the user has purchased the 1st subscription date (NOT the registration date) , and Month2 etc are the subsequent months from that date, varying for each account.
The format of the table for this report
I have managed to pull the first 2 months table, but can't figure out how to continue up to the 6th month. Thank you in advance!
SELECT F1.Id, F1.Month1, F2.Month2
FROM
(SELECT Id, AmountPerMonth AS Month1, ActionDate
FROM MONTLYSPEND
GROUP BY ID
HAVING MIN(ActionDate)) AS F1,
(SELECT t1.Id R, t2.AmountPerMonth AS Month2, MIN(t2.ActionDate)
FROM MONTLYSPEND t1
INNER JOIN MONTLYSPEND t2
ON t1.Id = t2.Id
AND t1.ActionDate < t2.ActionDate
GROUP BY t1.Id) AS F2
WHERE F1.id = F2.R
;
Turns out there were two ways - Stored Procedure, which takes too much memory, or using CASE WHEN, this pivots the table as well. Hope it's useful to people who have to generate reports showing various activity per user day by day or month by month on the x axis. The main difficulty I had was the fact that Month_1 (first purchased subscription) was a different date for every user. This report can be used to analyse your users behavior in the first 6 months of their subscription.
The report generated by this query looks like this:
+--------+----------+------------------+---------+---------+--------+
| UserId | Currency | FirstSubscrPurch | Month_1 | Month_2 | etc... |
+--------+----------+------------------+---------+---------+--------+
| 123 | GBP | 2010-05-27 | 34.00 | 27.00 | 0.00 |
+--------+----------+------------------+---------+---------+--------+
SELECT F6.USERID, F6.Currency, DATE_FORMAT(F6.FirstSubscrPurch, "%Y-%m-%d") AS FirstSubscrPurch, F6.MONTH_1, F6.MONTH_2,F6.MONTH_3, F6.MONTH_4, F6.MONTH_5, F6.MONTH_6, ROUND(((F6.MONTH_1+F6.MONTH_2+F6.MONTH_3+F6.MONTH_4+F6.MONTH_5+F6.MONTH_6)/6),2) AVERAGE, F6.CURRENCY
FROM (
SELECT
UserId, Currency, FirstSubscrPurch,
SUM(CASE WHEN YEAR_AND_MONTH_INDEX = 0 THEN TOTAL_AMOUNT_PAID ELSE 0 END) MONTH_1,
SUM(CASE WHEN YEAR_AND_MONTH_INDEX = 1 THEN TOTAL_AMOUNT_PAID ELSE 0 END) MONTH_2,
SUM(CASE WHEN YEAR_AND_MONTH_INDEX = 2 THEN TOTAL_AMOUNT_PAID ELSE 0 END) MONTH_3,
SUM(CASE WHEN YEAR_AND_MONTH_INDEX = 3 THEN TOTAL_AMOUNT_PAID ELSE 0 END) MONTH_4,
SUM(CASE WHEN YEAR_AND_MONTH_INDEX = 4 THEN TOTAL_AMOUNT_PAID ELSE 0 END) MONTH_5,
SUM(CASE WHEN YEAR_AND_MONTH_INDEX = 5 THEN TOTAL_AMOUNT_PAID ELSE 0 END) MONTH_6
FROM (
SELECT
hp.UserId, hp.Currency, MIN(hp.Date) AS FirstSubscrPurch,
CONCAT(YEAR(Date),'-',MONTH(Date)) AS YEAR_AND_MONTH,
TIMESTAMPDIFF( MONTH, CONCAT(YEAR(FIRST_PAYMENT_DATE),'-',MONTH(FIRST_PAYMENT_DATE),'-1'), CONCAT(YEAR(Date),'-',MONTH(Date),'-1')) AS YEAR_AND_MONTH_INDEX, -- generates string in format YYYY-M-D
MIN(Date) FIRST_PAYMENT_OF_MONTH,
MAX(Date) LAST_PAYMENT_OF_MONTH,
COUNT(*) NUM_PAYMENTS,
SUM(hp.Amount) TOTAL_AMOUNT_PAID,
SUM(hp.Credits) Credits
FROM payments hp
JOIN (
SELECT UserId, MIN(Date) FIRST_PAYMENT_DATE, ADDDATE(MIN(Date), INTERVAL 6 MONTH) SIX_MONTHS_AFTER_FIRST_PAYMENT
FROM payments hp
GROUP BY UserId
) USER_MIN_ID ON USER_MIN_ID.UserId = hp.UserId
AND hp.Date BETWEEN FIRST_PAYMENT_DATE AND CONCAT(YEAR(SIX_MONTHS_AFTER_FIRST_PAYMENT),'-',MONTH(SIX_MONTHS_AFTER_FIRST_PAYMENT),'-1')
GROUP BY UserId, Currency, YEAR_AND_MONTH
ORDER BY hp.UserId, hp.Date
) F
GROUP BY UserId, Currency
ORDER BY UserId DESC) F6;

Sql query for clubbing the data according to date

I have a table like this. Now I want to show the total of same dates of different status in single row.
What should be the query?
Expected Result
Created | Total1 | Total2 | Total3
2017-02-28 | 1 | 1 | 2
you could use a sum for case when for each status and group by
select
created
, sum( case when story_status ='Draft' then total else 0 end ) as Draft_count
, sum( case when story_status ='Private' then total else 0 end ) as Private_count
, sum( case when story_status ='Published' then total else 0 end ) as Published_count
from my_table
group by created
This will give you one row per date created, with columns for each story_status:
SELECT
`created`,
SUM(if(`story_status` = 'Draft',`total`,0)) as `Total Draft`,
SUM(if(`story_status` = 'Private',`total`,0)) as `Total Private`,
SUM(if(`story_status` = 'Published',`total`,0)) as `Total Published`
FROM table
GROUP BY `created`
ORDER BY `created`

How to do a SELECT for total from beginning until the specified date in MySQL?

I have entry table:
I need to do a SELECT to receive 'Date', 'Number of entries' (in that date), 'Total number of entries until that date'.
When I do the SELECT:
SELECT e1.*,
(select count(*) from entry where date(dateCreated) <= e1.date) as Total
from (
SELECT
DATE(e.dateCreated) as "Date",
count(e.dateCreated) as "No of Entries",
sum( case when e.premium='Y' then 1 else 0 end ) as Premium,
sum( case when e.free='Y' then 1 else 0 end ) as Free,
sum( case when e.affiliateID IS NOT NULL then 1 else 0 end) as Affiliate
FROM entry e
WHERE e.competitionID=166
GROUP BY DATE(e.dateCreated)
) as e1
ORDER BY Date DESC
I've got a result table
but the column 'Total' has a wrong data.
How the correct select should be? Is this logic of select is the best and more efficient one?
Here is a demo
If it is just the 5 vs 7 that is off I think it is because that subquery in your select list, which accesses the inline view e1 (which is filtered to competitionID = 166), is not itself filtered when also utilizing the original entry table (unfiltered). You have to filter the original table to that competitionID as well.
Notice line 3 in sql below (only change)
SELECT e1.*,
(select count(*) from entry where date(dateCreated) <= e1.date
and competitionID=166) as Total
from (
SELECT
DATE(e.dateCreated) as "Date",
count(e.dateCreated) as "No of Entries",
sum( case when e.premium='Y' then 1 else 0 end ) as Premium,
sum( case when e.free='Y' then 1 else 0 end ) as Free,
sum( case when e.affiliateID IS NOT NULL then 1 else 0 end) as Affiliate
FROM entry e
WHERE e.competitionID=166
GROUP BY DATE(e.dateCreated)
) as e1
ORDER BY Date DESC
Fiddle - http://sqlfiddle.com/#!9/e5e88/22/0

SQL - sum of some rows, minus sum of other rows

I have a table in mySQL with the following columns:
CUSTOMER_CODE | TRANS_TYPE | TRANS_VALUE
TRANS_TYPE could be either "DRINV" (a sale) or "DRCDT" (a credit).
I want to get the total sales per customer, so my query so far is:
SELECT CUSTOMER_CODE, SUM(TRANS_VALUE) as SALES FROM DR_TRANS GROUP BY CUSTOMER_CODE
Problem is this is totaling the sales and credits, instead of giving be sales minus credits. I want the results to be
SUM(TRANS_VALUE) where TRANS_TYPE = "DRINV" - SUM(TRANS_VALUE) where TRANS_TYPE = "DRCDT".
Is it possible to do this in a SQL query?
select customer_code,
sum(case
when trans_type = 'DRINV' then
trans_value
else
-trans_value
end) as net_sales
from dr_trans
group by customer_code
Yes, it is possible. Use CASE caluse:
SELECT CUSTOMER_CODE,
SUM(CASE WHEN TRANS_TYPE = 'DRINV' THEN TRANS_VALUE ELSE (- TRANS_VALUE) END ) as SALES
FROM DR_TRANS GROUP BY CUSTOMER_CODE

Retrieve query column as row

I have a table with following columns:
BillNo -- Integer
BillDate -- DateTime
Qty -- decimal
ItemName -- varchar
I want to retrieve results in this format:
**ITEMNAME...JAN-2011.....FEB-2011....MAR-2011**
ITEM1 ......... 20 ..............19................18
ITEM2 ......... 23 ..............10................9
I tried this query which is showing correct results but I want to convert third column to a row with distinct values:
SELECT ITEMNAME, SUM(QTY), DATE_FORMAT(BILLDATE,'%M-%Y') FROM BILLITEMS
GROUP BY BILLDATE
ORDER BY YEAR(BILLDATE) DESC, MONTH(BILLDATE), ITEMNAME;
Try to use query below but it will work for a specific year
SELECT ITEMNAME, year_bill, SUM(jan), SUM(feb), .... from (
select case when MONTH(BILLDATE) = 1 then QTY else 0 end as jan,
case when MONTH(BILLDATE) = 2 then QTY else 0 end as feb,
case when MONTH(BILLDATE) = 3 then QTY else 0 end as mar,
ITEMNAME,
YEAR(BILLDATE) as year_bill
from BILLITEMS) as temp
GROUP BY ITEMNAME, year_bill