Hi still getting my head around MySQL so was hoping someone may be able to shed some light on this one
I have a table named customers which has the following columns
msisdn BIGINT 20
join_date DATETIME
The msisdn is a unique value to identify customers.
There is a second table named ws_billing_all which has the following structure
id INTEGER 11 (Primary Key)
msisdn BIGINT 20
event_time DATETIME
revenue INTEGER
So this table stores all transactions for each of the customers in the customers table as identified by the msisdn.
What I need to do is to determine the amount from all customers that joined on a particular day after 30 days.
So for example, on the 2nd of Dec 2010, 1,100 customers were acquired. Based on the data in ws_billing_all, how much total revenue did the customers that joined on this day generate 30 days from this date.
I will probably need another table for this but not sure and really not sure on how to go about extracting this data. Any help would be appreciated.
#Cularis was very close... You only care about those customers that joined on the ONE DAY, and want all THEIR REVENUEs earned for the next 30 days... In this scenario, a customer would never have sales prior to their join date, so I didn't add an explicit between on their actual sales dates of consideration.
SELECT
date( c.Join_Date ) DateJoined,
count( distinct c.msisdn ) DistinctMembers,
count(*) NumberOfOrders,
SUM(w.revenue) AmountOfRevenue
FROM
customers c
JOIN ws_billing_all w
ON c.msisdn = w.msisdn
AND date( w.event_time ) <= date_add( c.Join_Date, INTERVAL 30 DAY )
WHERE
c.Join_Date >= SomeDateParameterValue
group by
date( c.Join_Date )
order by
date( C.Join_Date )
EDIT -- For clarification...
If you had 150 people join on Dec 1, 45 people on Dec 2, 83 people on Dec 3, you want to see the total revenue per group of people based on the day they joined going out 30 days of their sales... So...
Joined on Number of People Total Revenue after 30 days
Dec 1 150 $21,394 (up to Dec 31)
Dec 2 45 $ 4,182 (up to Jan 1)
Dec 3 83 $ 6,829 (up to Jan 2)
Does this better clarify what you want? Then we can adjust the query...
FINAL EDIT ...
I think I have what you INTENDED (with a count of orders too that might be useful). In the future, providing a sample output of something of complex nature would be helpful, even if it was as simple as I've done here.
With respect to my WHERE clause from the customers table.... Say you only cared about customers who joined within a given time frame, or only after a given date... THIS is where you would update the clause... if you want based on ALL people, then just remove it completely.
SELECT c.msisdn, SUM(w.revenue)
FROM customers c
INNER JOIN ws_billing_all w ON c.msisdn=w.msisdn
WHERE w.event_time BETWEEN c.join_date AND DATE_ADD(c.join_date, INTERVAL 30 DAY)
GROUP BY c.msisdn
You have to join both tables on the customer id. Then select all events that happened between the join date and 30 days after that. Group by the customer id and use SUM() to get total revenue per costumer.
Related
I m having a very tricky SQL question, maybe the trickiest I have had
suppose I have one table below
called table_1
Date
spend
Oct. 20
50
Oct. 19
40
Oct. 18
50
Oct. 17
60
Oct. 16
50
and now I need another table that sums up all the spend that I have made, before and include the every date. like to show every I have spend so far for each date.
And for each of the date.
Below is the table that I want compute
called table_2
Date
spent
Oct. 20
250 ( sum of all the spend before and includes Oct.20)
Oct. 19
200 ( sum of all the spend before and includes Oct.19)
Oct. 18
160 ( sum of all the spend before and includes Oct.18)
Oct. 17
110 ( sum of all the spend before and includes Oct.17)
Oct. 16
50 ( sum of all the spend before and includes Oct.16)
I have tried with table_1 left join itself with left join on date_1 <= date_2.
does not work.
Could someone please give me a hint for it?
You want a running total. You get this with the windw function SUM OVER.
select date, sum(spend) over(order by date) as sum_spent
from mytable
order by date desc;
And if you should suffer from having to use an old MySQL version that doesn't support window functions yet, here is an old-fashioned alternative:
select
date,
(select sum(spend) from mytable t2 where t2.date <= t.date) as sum_spent
from mytable t
order by date desc;
Supplementary to Thorsten Kettner's answer, LEFT JOIN you've made attempt also works
SELECT a.date, SUM(b.spend)
FROM table_1 a
LEFT JOIN table_1 b ON a.date >= b.date
GROUP BY a.date
I have a dataset where I need to find out New subscribers revenue.
These are subscribers that are paying either weekly or monthly depending on the subscription they are on.
The unique identifier is "customer" and the data is at timestamp level, but I want it rolled up at monthly level.
Now for each month, we need to find out revenue for only NEW subscribers.
Basically, imagine customers being on monthly/weekly subscriptions and we only want their FIRST Payments to be counted here.
Here's a sample dataset and
created customer amount
16-Feb-18 14:03:55 cus_BwcisIF1YR1UlD 33300
16-Feb-18 14:28:13 cus_BpLsCvjuubYZAe 156250
15-Feb-18 19:19:14 cus_C3vT6uVBqJC1wz 50000
14-Feb-18 23:00:24 cus_BME5vNeXAeZSN2 162375
9-Feb-18 14:27:26 cus_BpLsCvjuubYZAe 156250
....and so on...
here is the final desired output
yearmonth new_amount
Jan - 2018 100000
Feb - 2018 2000
Dec - 2017 100002
This needs to be done in MySQL interface.
Basically, you want to filter the data to the first customer. One method of doing this involves a correlated subquery.
The rest is just aggregating by year and month. So, overall the query is not that complicated, but it does consist of two distinct parts:
select year(created) as yyyy, month(created) as mm,
count(*) as num_news,
sum(amount) as amount_news
from t
where t.created = (select min(t2.created)
from t t2
where t2.customer = t.customer
)
group by yyyy, mm
We can have sql subquery for only the 1st payment of the new customer with
amount for every month and year
The query is as follows
SELECT month(created) as mm,year(created) as yyyy,
sum(amount) as new_amount
FROM t
WHERE t.created=(select min(t2.created) from t t2 where
t2.customer=t.customer)
I have the following table denoting a tutor teaching pupils in small groups. Each pupil has an entry into the database. A pupil may be alone or in a group. I wish to calculate the tutors "salary" as such: payment is based on time spent - this means that for each sitting (with one or more pupils) only one sitting will be calculated - distinct sittings! The start and end times are unix times.
<pre>
start end attendance
1359882000 1359882090 1
1359867600 1359867690 0
1359867600 1359867690 1
1359867600 1359867690 0
1360472400 1360477800 1
1360472400 1360477800 1
1359867600 1359867690 1
1359914400 1359919800 1
1360000800 1360006200 1
1360000800 1360006200 0
1360000800 1360006200 1
</pre>
This is what I tried: with no success - I can't get the right duration (number of hours for all distinct sittings)
SELECT YEAR(FROM_UNIXTIME(start)) AS year,
MONTHNAME(STR_TO_DATE(MONTH(FROM_UNIXTIME(start)), '%m')) AS month,
COUNT(DISTINCT start) AS sittings,
SUM(TRUNCATE((end-start)/3600, 1)) as duration
FROM schedules
GROUP BY
YEAR(FROM_UNIXTIME(start)),
MONTH(FROM_UNIXTIME(start))
Thanks for your proposals / support!
EDIT: Required results
Rate = 25
Year Month Sittings Duration Bounty
2013 February 2 2.2 2.2*25
2013 April 4 12.0 12.0*25
You could probably do something with subqueries, I've had a play with SQL fiddle, how does this look for you. Link to sql fiddle : http://sqlfiddle.com/#!2/50718c/3
SELECT
YEAR(d.date) AS year,
MONTH(d.date) AS month,
COUNT(*) AS sittings,
SUM(d.duration) AS duration_mins
FROM (
SELECT
DATE(FROM_UNIXTIME(s.start)) AS date,
s.attendance,
end-start AS duration
FROM schedules s
) d
GROUP BY
year,
month
I couldn't really see where attendance comes into this at present, you didn't specify. The inner query is responsible for taking the schedules, extracting a start date, and a duration (in seconds).
The outer query then uses these derived values but groups them up to get the sums. You could elaborate from here i.e. maybe you only want to select where attendance > 0, or maybe you want to multiply by attendance.
In this next example I have done this, calculating the duration in hours instead, and calculating the applicable duration for where sessions have >1 attendance along with the appropriate bounty assuming bounty == hours * rate : http://sqlfiddle.com/#!2/50718c/21
SELECT
YEAR(d.date) AS year,
MONTH(d.date) AS month,
COUNT(*) AS sittings,
SUM(d.duration) AS duration,
SUM(
IF(d.attendance>0,1,0)
) AS sittingsWorthBounty,
SUM(
IF(d.attendance>0,d.duration,0)
) AS durationForBounty,
SUM(
IF(d.attendance>0,d.bounty,0)
) AS bounty
FROM (
SELECT
DATE(FROM_UNIXTIME(s.start)) AS date,
s.attendance,
(end-start)/3600 AS duration,
(end-start)/3600 * #rate AS bounty
FROM schedules s,
(SELECT #rate := 25) v
) d
GROUP BY
year,
month
The key point here, is that in the subquery you do all the calculation per-row. The main query then is responsible for grouping up the results and getting your totals. The IF statements in the outer query could easily be moved into the subquery instead, for example. I just included them like this so you could see where the values came from.
I've been Googling for a few hours... thought this would be easy, but clearly not for me :)
I've got sales data in two tables and I want to generate a weekly sales report for a specific item. For this purpose, I don't care about dollar values, just number of units. An a "week" is either a calendar week (whatever start day, I don't care) or just 7-day chunks back from current (so week 1 is the last 7 days, week 2 is 8 - 15 days ago, etc) - whichever is easier. I'm simply trying to monitor sales trends over time. Preferably it would span back over years so that if its the first week of January, for example, it wouldn't show just one record.
The data comes from ZenCart. The relevant tables/column structure is here:
Table "orders" has columns: orders_id, date_purchased
Table "orders_products" has columns: orders_id, products_id, product_quantity
Where I'm having trouble is with the joins and syntax.
This worked for my needs:
SELECT o.date_purchased, CONCAT(YEAR(o.date_purchased), LPAD(WEEK(o.date_purchased), 2, '0')) as weekyear, op.products_id, SUM( op.products_quantity )
FROM orders_products op
LEFT JOIN orders o ON op.orders_id = o.orders_id
WHERE op.products_id = 331
GROUP BY weekyear
ORDER BY weekyear
If you have some date/datetime/timestamp column, you can use the week function in your where clause
select week(now()) as week, sum(units) as total
from sales
where week(sales_date) = week(now());
or the previous week
select week(now()) - 1 as week, sum(units) as total
from sales
where week(sales_date) = week(now()) - 1;
You must take care for the year wrap around from week 52/53 to week 0/1.
SQLFiddle for testing.
In order to take care of the year end wrap. for instance, week(12/30/2018)=52 and week(12/31/2018)=52 both are considered week 52 of 2018. the first day of 2019 starts on a Tuesday. you can write a case statement as follows to move 12/30/2018 and 12/31/2018 to the first week of 2019. so that you will have a complete 7 days week to compare:
case when order_date in ( '2018-12-30', '2018-12-31')
then 0
else week(order_date)
end as order_week
I am running MYSQL 5.1.41 on Ubuntu 10.04.
I have two tables. stocks which contains basic info about a group of stocks and has the following columns: pk, name, pur_date, pur_price, avg_vol, mkt_cap. The other table is data which contains price history about the stocks in the stocks table. The data table contains the following columns: pk, ticker, date, open,high, low, close, volume, adj_close.
I need a query that will show the high for a stock since it's purchase date and the date it occurred.
I have this query:
SELECT ticker, date, MAX(high)
FROM data, stocks
WHERE ticker = sym AND date > pur_date
GROUP BY ticker
ORDER BY ticker
LIMIT 0, 100
The query will give me each stocks high but always returns the latest date in the data table, which happens to be 2011-12-23. How do I change the query to show the date the stock reached its high?
Thanks for your help
That's the classic greatest-per-group issue. One solution is to query the maximum high for the ticket in a subquery:
select ticker
, date
, high
from data d
join stocks s
on d.ticker = s.sym
where d.date > pur_date
and d.high =
(
select max(high)
from data d2
where d2.ticker = d.ticker
and d2.date > pur_date
)
See Quassnoi's explain extended blog for a detailed discussion.
You originally had your grouping by stock ticker, which may not give the correct expected results as I'll explain later. I've actually done a pre-query on a per purchase stock entry and getting the highest price since it was purchased... Consider the following scenario.
Person buys 100 Shares of Stock X on Jan 1 for $20 per share. Buys ANOTHER set of 100 shares on Jan 25 at $23 per share, and another 100 on Feb 18 at $24 per share. The actual data shows Stock X had a high on Jan 22 (before second purchase) of $27 per share then dropped by the time the $23 on Jan 25... shifted down/up from there before Feb purchase, but only on Feb 27 did it kick back up to $25 per share.
The first trade
Jan 1 Bought $20 would show a high of $27 on Jan 22
Jan 25 Bought $23 would show the high of $25 on Feb 27
Feb 18 Bought $24 would also show high of $25 on Feb 27
So grouping by ticker might not necessarily show. Now, above scenario being shown, would you want from here that Stock X across-the-board for all purchases showed a high of $27? even though the most recent purchases never saw that price?
select
s2.*,
d2.*
from
( select
s.pk,
s.sym,
max( d.high ) as HighSincePurchDay
from
stocks s
join data d
on s.sym = d.ticker
AND s.pur_date <= d.date
group by
s.pk
) PreQuery
JOIN stocks s2
on PreQuery.PK = s2.PK
JOIN data d2
on PreQuery.Sym = d.Ticker
AND s.Pur_Date <= d.Date
AND d.high = PreQuery.HighSincePurchDay