Mysql in-time query - mysql

I'm in need of some help structuring in-time queries. There's a few of them I need - but I think that if I can be shown how to do one, I can figure out the others.
What I'm after:
-Rolling 12 month view of 'inactive accounts'...ie number of accounts that have not placed an order in the 12 months prior.
-This ideally will be a subquery (in a much larger script) joining back on to a dates table (see below)
January 2015 | # of customers with no orders from 1/2014-1/2015
February 2015 | # of customers with no orders from 2/2014-2/2015
March 2015 | # of customers with no orders from 3/2014-3/2015
etc...
What I'm having trouble wrapping my mind around is how I'd structure a where clause to ensure that it scans all orders and only returns the total of account ID's that had not placed an order in the year prior to that month. I've used different combinations of DATEDIFF, DATESUB etc.
SELECT DATE_FORMAT(order_datetime, '%Y-%m'), COUNT DISTINCT (account_id)
FROM warehouse.orders
JOIN warehouse.accounts ON xyz
WHERE...
It feels like I'm on the right path - I just keep mentally going in circles trying to figure this out.
Cheers and thanks in advance.

I don't have enough reputation points to simply comment on your question. I don't fully understand it though.
Are you using SQLServer/TSQL or MySQL?
Do you want to have just one column which calculates the last 12 months' rolling average or 12 columns for the rolling average each month? If it is just one figures for the last 12 months tolling do you want that to be from the current day or the beginning of that month?
If it was SQL Server and a rolling 12 months to now, the calculation could be:
SELECT SUM(CASE WHEN DATEDIFF(y,GETDATE(),order_date_time) < 1 THEN COUNT(DISTINCT account_id) END) as January2015
If you're using MySQL replace GETDATE() with NOW()
If you want one value rolling but to the beginning of the month then you could use:
SELECT SUM(CASE WHEN DATEDIFF(y,DATEADD(M, DATEDIFF(M, 0, GETDATE()), 0),order_date_time) < 1 THEN COUNT(DISTINCT account_id) END) as January2015
If I've missed the point entirely, please let me know and I'll happily amend the answer

You should query between dates, in order to get the count of events for each id.
select case
when count(account_id)<0 then 'INACTIVE'
when count(account_id)>0 then 'ACTIVE'
from warehouse.orders
where data_format(order_datetime, '%m/%Y') between '1/2014' and '1/2015'
group by account_id)

Related

Mysql query that finds dates for the previous month from meta_value

I have created a view called acquity_fields with 4 columns (see also view from phpMyAdmin attached):
meta_id; post_id; meta_key; meta_value
I was using this post Construct MySQL query ( meta_key/meta_value table) to help me to create a query so that I can pull the last month (e.g Sept 1-30 inclusive) as well as August for number of clients.
But I need to walk first so I wanted to display all months with number of clients in each then add in the additional statements for last month and previous.
Here is the query I put together for getting all the months and clients,
SELECT COUNT(*) as Clients, MONTHNAME(FROM_UNIXTIME(meta_key = 'wpcf-acquity-date')) as Month
FROM acquity_fields
WHERE (meta_key = 'wpcf-acquity-date')
GROUP BY Month
but it seems to be putting all the clients into one month and displaying it as:
Clients | Month
----------------------
399 | January
I am not sure if its the time conversion, but I am stumped to what is causing this. Any help would be great and thanks in advance!
View acquity_fields in phpmyadmin
In your select part of the query, FROM_UNIXTIME() takes in a timestamp, so try this:
SELECT COUNT(*) as Clients, MONTHNAME(FROM_UNIXTIME(meta_value)) as Month
FROM acquity_fields
WHERE (meta_key = 'wpcf-acquity-date')
GROUP BY Month
(meta_key = 'wpcf-acquity-date') is a WHERE condition, not a timestamp integer. If you have something that's not a timestamp, the system will treat it as a default date, and the output will become December or January depending on your settings.

Query with three tables, no common column

I've just started a job and my boss wants me to learn mySQL so please bear with me, i've been learning for only 2 days and i'm not that good at it yet.
So i've been given 3 tables and several tasks to do.
The tables are:
mobile_log_messages_sms
mobile_providers
service_instances
And in them i've got to:
Find out how many messages there were in the last 25 days and how
much income did they make
Then i need to group them by day (so per day, exclude hours) and
provider name.
Also i need to ignore all the messages that have an empty string
under the service column
Also i need to ignore the messages that made 0 income and count only
those that have the column service_enabled = 1
And then i need to sort it descending, by date.
in the tables
mobile_log_messages_sms:
message_id - used to count the messages
price - using for price obviously, exlude those with 0
time - date in yyyy/mm/dd hh:mm:ss format
service - exclude all those that have an empty string (or null)
mobile_providers
provider_name - to use to group with
service_instances
enabled - only use if value is 1
I've started with:
SELECT message_id, price, time
FROM mobile_log_messages_sms
WHERE time BETWEEN '2017-02-26 00:00:00'
AND time AND '2017-03-22 00:00:00'
But i need to change the date format and then use the JOIN commands but i don't know how, and i know i need to add more to it, but i'm stumped even at the start. Also the starting just lists the messages but i need to count the total sum of the income (price) per day.
Can anyone point me in the right direction at least since i'm still a noob? Many thanks in advance and sorry if i worded something badly, english is not my first language.
Find out how many messages there were in the last 25 days and how much income did they make
1.
SELECT COUNT(message_id), SUM(price)
FROM mobile_log_messages_sms
WHERE CAST(time AS DATE) BETWEEN DATE_SUB(CURRENT_DATE,INTERVAL 25 DAY)
AND CURRENT_DATE;
2.
SELECT COUNT(message_id), SUM(price)
FROM mobile_log_messages_sms
WHERE CAST(time AS DATE) BETWEEN DATE_SUB(CURRENT_DATE,INTERVAL 25 DAY)
AND CURRENT_DATE
GROUP BY CAST(time AS DATE);
3.
SELECT COUNT(message_id), SUM(price)
FROM mobile_log_messages_sms
WHERE CAST(time AS DATE) BETWEEN DATE_SUB(CURRENT_DATE,INTERVAL 25 DAY)
AND CURRENT_DATE AND service IS NULL
GROUP BY CAST(time AS DATE);
rest can't done with join so make sure that at least one column should be common in tables.

Rolling month script

I'm trying to provide a rolling 12 month view of our 'dormant' clients by region each month (dormant = haven't placed an order in past 12 months). Below is stripped down piece of the script (minus the necessary joins).
select region, count(clientID)as TotalDormant
FROM clients
WHERE test_account = 'NO'
AND DATEDIFF(curdate(), last_order_date) > 365
GROUP BY 1
Returning...
Region Total Dormant
ROW 500
US 1000
However...because of the curdate() it's only returning the dormant customers who have been inactive for a full year leading up to today (9/17/2015). I need it to return the number of dormant clients we had on each of the past 11 months.
Any help on what I'll need to do to return the number dormant for each month on a rolling 12m basis by region?
I have tried inner join, subqueries etc...but they all wind up messing up even septembers data (which is accurate using the basic query above). So I decided to strip it down, ask for advice, and build from there.
Use the DATE_FORMAT function to get your month in the date:
select region, count(clientID) as TotalDormant,
DATE_FORMAT(last_order_date,'%Y %m') AS dormantSince
FROM clients
WHERE test_account = 'NO'
AND DATEDIFF(curdate(), last_order_date) > 365
GROUP BY DATE_FORMAT(last_order_date,'%Y %m');
When also placed in the GROUP BY, the query will give your the dormance since a certain month.

GROUP BY date and sum together forward yes but backward no

I have a table
PEOPLE, DATE, DELETED
Amanda, 2015-03-01, Null
Ray, 2015-03-01, Null
Moe, 2015-04-01, Null
Yan, 2015-05-01, Null
Bee, 2015-05-05, 2015-06-12
now I need to group it and sum it with months like this:
March: 2 people
April: 3
May: 5
June: 5
July: 4
so new people should not be counted in previous month but they should be in next months for my range (January - June). And if man is DELETED, he should be counted together with another people last time in month when he has been deleted.
How to write query for this?
This can be at least solved using running totals. This just the outline how to do it, you'll need to do some work for the actual solution:
select people, date, 1 as persons from yourtable
union all
select people, deleted, -1 as persons from yourtable where deleted is not null
Then do a running total of this data, so that you sum the +-1 persons -field, and that should give you the amount of people that are there so far.
For the events happening in the middle of the month, you'll have to adjust the date to be the start of that or the next month whichever way you want them to be calculated.
If you need also those months when no changes happened, you'll probably need a table that contains the first day of each month for the biggest range of dates you'll ever need, for example 1.1.2000 - 1.12.2100.

MySQL Group By Order and Count(Distinct)

What is the best way to think about the Group By function in MySQL?
I am writing a MySQL query to pull data through an ODBC connection in a pivot table in Excel so that users can easily access the data.
For example, I have:
Select
statistic_date,
week(statistic_date,4),
year(statistic_date),
Emp_ID,
count(distict Emp_ID),
Site
Cost_Center
I'm trying to count the number of unique employees we have by site by week. The problem I'm running into is around year end, the calendar years don't always match up so it is important to have them by date so that I can manually filter down to the correct dates using a pivot table (2013/2014 had a week were we had to add week 53 + week 1).
I'm experimenting by using different group by statements but I'm not sure how the order matters and what changes when I switch them around.
i.e.
Group by week(statistic_date,4), Site, Cost_Center, Emp_ID
vs
Group by Site, Cost_Center, week(statistic_date,4), Emp_ID
Other things to note:
-Employees can work any number of days. Some are working 4 x 10's, others 5 x 8's with possibly a 6th day if they sign up for OT. If I sum the counts by week, I get anywhere between 3-7 per Emp_ID. I'm hoping to get 1 for the week.
-There are different pay code per employee so the distinct count helps when we are looking by day (VTO = Voluntary Time Off, OT = Over Time, LOA = Leave of Absence, etc). The distinct count will show me 1, where often times I will have 2-3 for the same emp in the same day (hits 40 hours and starts accruing OT then takes VTO or uses personal time in the same day).
I'm starting with a query I wrote to understand our paid hours by week. I'm trying to adapt it for this application. Actual code is below:
SELECT
dkh.STATISTIC_DATE AS 'Date'
,week(dkh.STATISTIC_DATE,4) as 'Week'
,month(dkh.STATISTIC_DATE) as 'Month'
,year(dkh.STATISTIC_DATE) as 'Year'
,dkh.SITE AS 'Site ID Short'
,aep.LOC_DESCR as 'Site Name'
,dkh.EMPLOYEE_ID AS 'Employee ID'
,count(distinct dkh.EMPLOYEE_ID) AS 'Distinct Employee ID'
,aep.NAME AS 'Employee Name'
,aep.BUSINESS_TITLE AS 'Business_Ttile'
,aep.SPRVSR_NAME AS 'Manager'
,SUBSTR(aep.DEPTID,1,4) AS 'Cost_Center'
,dkh.PAY_CODE
,dkh.PAY_CODE_SHORT
,dkh.HOURS
FROM metrics.DAT_KRONOS_HOURS dkh
JOIN metrics.EMPLOYEES_PUBLIC aep
ON aep.SNAPSHOT_DATE = SUBDATE(dkh.STATISTIC_DATE, DAYOFWEEK(dkh.STATISTIC_DATE) + 1)
AND aep.EMPLID = dkh.EMPLOYEE_ID
WHERE dkh.STATISTIC_DATE BETWEEN adddate(now(), interval -1 year) AND DATE(now())
group by dkh.SITE, SUBSTR(aep.DEPTID,1,4), week(dkh.STATISTIC_DATE,4), dkh.STATISTIC_DATE, dkh.EMPLOYEE_ID
The order you use in group by doesn't matter. Each unique combination of the values gets a group of its own. Selecting columns you don't group by gives you somewhat arbitrary results; you'd probably want to use some aggregation function on them, such as SUM to get the group total.
Grouping by values you derive from other values that you already use in group by, like below, isn't very useful.
week(dkh.STATISTIC_DATE,4), dkh.STATISTIC_DATE
If two rows have different weeks, they'll also have different dates, right?