How to count new users in last month in SQL? - mysql

I want to know how many new users we have last month, and how many of them have turned into buyers while I can not figure it out smoothly.the following is what I coded.
SELECT COUNT(DISTINCT(PRODUCT_ID))
FROM ORDER_TABLE AS O
INNER JOIN CUSTOMER_TABLE AS C
ON O.CUSTOMER_ID=C.CUSTOMER_ID
WHERE DATEDIFF(MONTH,ORDER_DATE,GETDATE())<=1
And there is another question which has confused me a lot: Which category have the highest YEAR BY YEAR growth in terms of revenue in 2016?

This should do it...
SELECT COUNT(Customer_ID)
FROM Customer_Table
WHERE Customer_ID IN (
SELECT Customer_ID
FROM Order_Table
)
AND DATEDIFF(MONTH, First_Visit, GETDATE()) <= 1

Guessing ...
This gives a list of the new users last month.
SELECT Customer_ID, Country, Gender
FROM Customer_Table
WHERE First_Visit >= (LAST_DAY(CURDATE()) + INTERVAL 1 DAY) - INTERVAL 2 MONTH
AND First_Visit < (LAST_DAY(CURDATE()) + INTERVAL 1 DAY) - INTERVAL 1 MONTH
That date range, given that today is 2017-08-14, looks like this after all the date arithmetic. That means "the calendar month immediately preceding this day."
WHERE First_Visit >= '2017-07-01'
AND First_Visit < '2017-08-01'
The Number of new visitors last month is a simple summary of that query.
SELECT COUNT(*)
FROM Customer_Table
WHERE First_Visit >= (LAST_DAY(CURDATE()) + INTERVAL 1 DAY) - INTERVAL 2 MONTH
AND First_Visit < (LAST_DAY(CURDATE()) + INTERVAL 1 DAY) - INTERVAL 1
Now, to elaborate a bit. How do we tell if a new user has purchased anything? We look in the order table. Something like this will do it.
SELECT C.Customer_ID, SUM(O.Order_Amount) Total_Order_Amount
FROM Customer_Table C
LEFT JOIN Order_Table O ON C.Customer_ID = O.Customeer_ID
WHERE First_Visit >= (LAST_DAY(CURDATE()) + INTERVAL 1 DAY) - INTERVAL 2 MONTH
AND First_Visit < (LAST_DAY(CURDATE()) + INTERVAL 1 DAY) - INTERVAL 1 MONTH
GROUP BY C.Customer_ID
This gives you a list of new customers, with a column showing how much each has ordered. So a NULL or 0 in the Total_Order_Amount column means a new customer who has never ordered anything.
Pro tip:
Incomplete and vague requirements are definitely part of stupid professor tricks. But they are also part of the world of information technology. Often a big part of a assignment, or a contract, or a project, is taking ridiculously vague requirements like the ones you've been given and refining them into something useful.

Related

How to count only business days (Monday to Friday) per month between two dates in MySQL 5.7?

I have the following table called vacations, where the employee id is displayed along with the start and end date of their vacations:
employee
start
end
1001
26/10/21
22/11/21
What I am looking for is to visualize the number of vacation days that each employee had, but separating them by month and without non-working days (Saturdays and Sundays).
For example, if you wanted to view the vacations for employee 1001, the following result should be displayed:
days
month
4
10
16
11
I have the following query that I have worked with:
SELECT id_employee,
EXTRACT(YEAR_MONTH FROM t.Date) as YearMonth,
COUNT(1) as Days
FROM (SELECT v.id_employee,
DATE_ADD(v.start, interval s.seq - 1 DAY) AS Date
FROM vacations v
CROSS JOIN seq_1_to_100 s
WHERE DATE_ADD(v.start, interval s.seq - 1 DAY) <= v.end
ORDER BY v.id_employee, , v.start, s.seq
) t
GROUP BY id_employee,
EXTRACT(YEAR_MONTH FROM t.Date)
With this query I separate the days between a range of two dates with their respective month, but how could I adapt it to stop considering Saturdays and Sundays? I'm working with MySQL 5.7 in phpMyAdmin
instead of count sum the compaarison of weekday function, which give what day it is .
But you should always save fates n a valid mysql manner 2021-10-28
SELECT id_employee,
EXTRACT(YEAR_MONTH FROM t.Date) as YearMonth,
SUM(WEEKDAY(`Date`) < 5) as Days
FROM (SELECT v.id_employee,
DATE_ADD(v.start, interval s.seq - 1 DAY) AS Date
FROM vacations v
CROSS JOIN seq_1_to_100 s
WHERE DATE_ADD(v.start, interval s.seq - 1 DAY) <= v.end
ORDER BY v.id_employee, v.start, s.seq
) t
GROUP BY id_employee,
EXTRACT(YEAR_MONTH FROM t.Date)

month on month records

Apologies if my question is structured incorrectly, first time user.
I would like to get all records from the current DateTime and previous month for the same date range e.g. 01st-15th. The date field has a timestamp so would like all the records to the hour and minute.
select
'Total' as 'Measure',
sum(pa.amount) as 'Current Month'
from pay as pa
inner join mem as me on pa.me_id = me.me_id
where pa.pa_completed between last_day(current_date() - interval 1 month) +
interval 1 day
and if(current_date() = current_date(),current_timestamp(),current_date())
group by 1
union all
select
'Total' as 'Measure',
sum(pa.amount) as 'Last Month'
from pay as pa
inner join mem as me on pa.me_id = me.me_id
where pa.pa_completed between last_day(current_date() - interval 2 month) +
interval 1 day
and if(current_date() = current_date(),current_timestamp() - interval 1
month,current_date() - interval 1 month)
group by 1
The where clause in the above codes does not seem to be returning the correct records. I have cross checked the output on both sets of SQL to our admin system and the figures are slightly off.
Is there something I am doing wrong in the code? or is there a better solution to get the output I am after?
I will be using the above code on a dashboard so the current_date() will change everyday.

Introducing a new column for previous month sum

I am trying to introduce a new column for my query, it currently counts sum of expenses in this month, the new column should display last months expences. I am not quite sure where to place it.
SELECT cat.id_kat,
cat.nazwa,
coalesce(exp.tot, 0) AS PriceTotal
FROM wydatki_kategorie cat
LEFT JOIN
(SELECT wydatki_wpisy.kategoria,
sum(wydatki_wpisy.brutto) AS tot
FROM wydatki_wpisy
LEFT JOIN wydatki ON wydatki_wpisy.do_wydatku = wydatki.id_wydatku
WHERE MONTH(wydatki.data_zakupu) = MONTH(CURRENT_DATE())
AND wydatki.id_kupujacy = 1
GROUP BY wydatki_wpisy.kategoria) exp ON cat.id_kat = exp.kategoria
Possibly might be needed ( if I'm not wrong ) - Where clause for the previous month.
wydatki.data_zakupu >= DATE_ADD(LAST_DAY(DATE_SUB(NOW(), INTERVAL 2 MONTH)), INTERVAL 1 DAY) AND
wydatki.data_zakupu<= DATE_SUB(NOW(), INTERVAL 1 MONTH)
SQL Fiddle example
Two things.
First, if you stop using WHERE MONTH(wydatki.data_zakupu) = MONTH(CURRENT_DATE()) to choose your dates you'll get three benefits.
Your date searching will become sargable: an index will speed it up.
You'll get a more general scheme for choosing months.
If you have multiple years' worth of data in your tables, things will work better.
Instead, in general use this sort of expression to search for the present month. You already figured out most of this.
WHERE wydatki.data_zakupu >= LAST_DAY(CURRENT_DATE()) + INTERVAL 1 DAY - INTERVAL 1 MONTH
AND wydatki.data_zakupu < LAST_DAY(CURRENT_DATE()) + INTERVAL 1 DAY - INTERVAL 0 MONTH
This looks for all datetime values on or after midnight at the first day of the present month, and before, but not on <, midnight at the first day of next month.
It generalizes to any month you want. For example,
WHERE wydatki.data_zakupu >= LAST_DAY(CURRENT_DATE()) + INTERVAL 1 DAY - INTERVAL 2 MONTH
AND wydatki.data_zakupu < LAST_DAY(CURRENT_DATE()) + INTERVAL 1 DAY - INTERVAL 1 MONTH
gets you last month. This also works when the current month is January, and it works when you have multiple years' worth of data in your tables.
These expressions are a little verbose because MySQL doesn't have a FIRST_DAY(date) function, only a LAST_DAY(date) function. So we need all that + INTERVAL 1 DAY monkey business.
Second, pulling out a previous month's data is as simple as adding another LEFT JOIN ( SELECT... clause to your table, like so. (http://sqlfiddle.com/#!9/676df4/13)
SELECT ...
coalesce(month1.tot, 0) AS LastMonth
FROM wydatki_kategorie cat
LEFT JOIN
...
LEFT JOIN
(SELECT wydatki_wpisy.kategoria,
sum(wydatki_wpisy.brutto) AS tot
FROM wydatki_wpisy
LEFT JOIN wydatki ON wydatki_wpisy.do_wydatku = wydatki.id_wydatku
WHERE wydatki.data_zakupu >= LAST_DAY(CURRENT_DATE()) + INTERVAL 1 DAY - INTERVAL 2 MONTH
AND wydatki.data_zakupu < LAST_DAY(CURRENT_DATE()) + INTERVAL 1 DAY - INTERVAL 1 MONTH
AND wydatki.id_kupujacy = 1
GROUP BY wydatki_wpisy.kategoria
) month1 ON cat.id_kat = month1.kategoria
As you can see, the date range WHERE clause here gets the previous month's rows.

How to SELECT last calender month (not the interval)?

I have date time field called transaction_date, in a report i need to select last calendar month, how do i do this ? (this should work for a month like January too)
I came up with following but this only works if the month is NOT january,
SELECT SUM(amount) AS pay_month FROM `users_payment` WHERE MONTH(transaction_datetime)= MONTH(NOW()) AND YEAR(transaction_datetime)=YEAR(NOW())
there are lot of examples using INTERVAL functions but this only select the time interval not the calendar month as i wanted too..
like
SELECT SUM(amount) AS `year_month` FROM `users_payment` WHERE DATE_ADD(NOW(), INTERVAL -1 MONTH) < transaction_datetime
but this is not what i want, i want to select sales sum of the DECEMBER only last year (remember there are other years too in the table which i dont want i.e 1979, 1981...etc)
same report next section, i need to select last 2 calender months, I dont know have any idea on how to do this too.
Have you tried the following
SELECT SUM(amount) AS `year_month` FROM `users_payment`
WHERE MONTH(DATE_ADD(NOW(), INTERVAL -1 MONTH)) = MONTH(transaction_datetime)
The above should work to show previous month; it does not distinguish between years however.
On second thought, I see what you are trying to do - To get all the transactions for a given month. Try something like this instead.
SELECT SUM(amount) AS `year_month` FROM `users_payment`
WHERE transaction_datetime BETWEEN date_format(NOW() - INTERVAL 1 MONTH, '%Y-%m-01')
AND last_day(NOW() - INTERVAL 1 MONTH)
This will list all the transactions for the previous calendar month. Alter the INTERVAL values to select multiple months.
You can try this--
SELECT SUM(amount) AS pay_month FROM `users_payment` WHERE
PERIOD_ADD(DATE_FORMAT(NOW(),'%Y%m'), -1) = DATE_FORMAT(transaction_datetime,'%Y%m')

Optimize a subquery searching for records in another table based on dates not in the past 360 days

Problem:
Find people whose birthdays are tomorrow (table a), who havent got a record with an issue date set in the past 360 days from (table b)
Table a
ID, DOB
Table b
ID, PID, Issued
I've got a query but it's pretty slow, not sure if a join would be quicker - any help appreciated..
SELECT a.ID, a.DOB FROM a
WHERE MONTH(a.DOB)=MONTH(now()) # match month
AND DAYOFMONTH(a.DOB)=DAYOFMONTH(now()+ INTERVAL 1 DAY) # match day of month
AND (
SELECT COUNT(*) FROM b
WHERE b.PID = a.ID
AND b.Issued < DATE_SUB(SYSDATE(), INTERVAL 360 DAY)
) < 1 # hacky subquery to find not issued in past 360 days
SELECT *
FROM A
LEFT JOIN B
ON A.Id = B.PID AND B.Issued >= DATE_SUB(CURDATE(), INTERVAL 360 DAY)
WHERE B.ID IS NULL AND
DATE_ADD(A.DOB, INTERVAL YEAR(CURDATE()) - YEAR(A.DOB) YEAR) =
DATE_ADD(CURDATE(), INTERVAL 1 DAY)