order unique accounts by date - sql

I have a table:
create table remote (account int ,datecreated datetime,status int)
insert into remote (account , datecreated,status)
values
(123,'2015-08-25',1),
(123,'2015-08-25',1),
(123,'2015-09-26',1),
(1238,'2015-08-25',1),
(123,'2014-08-25',1),
(123,'2014-08-26',1),
(1238,'2014-08-25',1),
(1238,'2014-08-25',1),
(1235,'2014-08-25',1),
(1234,'2014-09-22',1),
(1234,'2014-09-22',1),
(1234,'2014-10-29',1),
(1236,'2014-10-25',1);
From here I would like to get the unique account count for each month/year where status=1
For example using the data above:
the output would be
count | month
-------------
1 |9/2015
2 |8/2015
2 |10/2014
1 |9/2014
3 |8/2014
How can I make this work?
I use sql 2012.

Use Group by month and year of datecreated to skip day part in count. use the same month and year in order by desc . Then Concatenate the month and year to get the result
SELECT [Count],
[Mon/Year]= CONVERT(VARCHAR(2), [Month]) + '/' + CONVERT(VARCHAR(4), [year])
FROM (SELECT [year]=Year(datecreated),
[month]= Month(datecreated),
[Count]= Count(distinct account)
FROM remote
GROUP BY Year(datecreated),
Month(datecreated)) a
ORDER BY [year] DESC,[Month] DESC
Result
Count Mon/Year
----- --------
1 9/2015
3 8/2015
2 10/2014
1 9/2014
5 8/2014

This is a group by query with a filter and some datetime logic:
select year(datecreated) as yr, month(datecreated) as mon, count(*)
from remote
where status = 1
group by year(datecreated), month(datecreated)
order by yr desc, mon desc;
This puts the year and month into separate columns. You can concatenate them together into a single value if you really want to.

Related

sql user retention calculation

I have a table records like this in Athena, one user one row in a month:
month, id
2020-05 1
2020-05 2
2020-05 5
2020-06 1
2020-06 5
2020-06 6
Need to calculate the percentage=( users come both prior month and current month )/(prior month total users).
Like in the above example, users come both in May and June 1,5 , May total user 3, this should calculate a percentage of 2/3*100
with monthly_mau AS
(SELECT month as mauMonth,
date_format(date_add('month',1,cast(concat(month,'-01') AS date)), '%Y-%m') AS nextMonth,
count(distinct userid) AS monthly_mau
FROM records
GROUP BY month
ORDER BY month),
retention_mau AS
(SELECT
month,
count(distinct useridLeft) AS retention_mau
FROM (
(SELECT
userid as useridLeft,month as monthLeft,
date_format(date_add('month',1,cast(concat(month,'-01') AS date)), '%Y-%m') AS nextMonth
FROM records ) AS prior
INNER JOIN
(SELECT
month ,
userid
FROM records ) AS current
ON
prior.useridLeft = current.userid
AND prior.nextMonth = current.month )
WHERE userid is not null
GROUP BY month
ORDER BY month )
SELECT *, cast(retention_mau AS double)/cast(monthly_mau AS double)*100 AS retention_mau_percentage
FROM monthly_mau as m
INNER JOIN monthly_retention_mau AS r
ON m.nextMonth = r.month
order by r.month
This gives me percentage as 100 which is not right. Any idea?
Hmmm . . . assuming you have one row per user per month, you can use window functions and conditional aggregation:
select month, count(*) as num_users,
sum(case when prev_month = dateadd('month', -1, month) then 1 else 0 end) as both_months
from (select r.*,
cast(concat(month, '-01') AS date) as month_date,
lag(cast(concat(month, '-01') AS date)) over (partition by id order by month) as prev_month_date
from records r
) r
group by month;

how can i create a loop in my SQL query that will look for each week out of the year and return the top 10 values for each week?

I am writing a query that returns the total number of submissions by person per week. Like Below...
Person WeekNumber Total
ABC 1 12
ADE 1 10
ACD 1 8
LKJ 2 15
HJK 2 14
FGH 2 12
So far, I have the query to do everything EXCEPT being able to select the top Person from EACH WEEK. I am thinking I might need to use a loop to do this but just trying to see if anyone might have a better/easier idea?
Here is my query:
Select sub.Person, sub.WeekNumber, sum(sr_id_count) as TotalSRID
from
(
SELECT
Person,
DATEDIFF(week, '2016-12-25', create_date) AS WeekNumber,
count(SR_ID) as SR_ID_COUNT
from [dbo].[tbl_Hist]
where create_date >= '01/01/2017'
and SR_STatus <> 'Canceled'
and Created_by <> 'System'
group by person, create_date
) sub
group by sub.Person, sub.WeekNumber
order by WeekNumber, TotalSRID desc
The syntax is SQL Server, so I will assume that is the database you are using. If so, you can use row_number(). To get the top person per week:
select *
from (select Person, datediff(week, '2016-12-25', create_date) AS WeekNumber,
count(SR_ID) as SR_ID_COUNT,
row_number() over (partition by datediff(week, '2016-12-25', create_date order by count(SR_ID) desc) as seqnum
from [dbo].[tbl_Hist]
where create_date >= '2017-01-01' and SR_STatus <> 'Canceled' and
Created_by <> 'System'
group by person, datediff(week, '2016-12-25', create_date)
) sub
where seqnum = 1;
If you want the top 10 per week, then use seqnum <= 10.

SQL Server : getting year and month

I have a SQL Server table like this:
http://sqlfiddle.com/#!2/a15dd/1
What I want to do is display the latest year and month where trades were made.
In this case, i want to display
ID: 1
Year: 2013
Month: 11
Trades: 2
I've tried to use:
select
id, MAX(year), MAX(month)
from
ExampleTable
where
trades > 0
group by
id
Do I have to concatenate the columns?
You can use ROW_NUMBER to assign each row a number based on it's relative position (as defined by your order by):
SELECT ID,
Year,
Month,
Trades,
RowNum = ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Year DESC, Month DESC)
FROM ExampleTable
WHERE Trades > 0;
With your example data this gives:
ID YEAR MONTH TRADES RowNum
1 2013 11 2 1
1 2013 4 42 2
Then you can just limit this to where RowNum is 1:
SELECT ID, Year, Month, Trades
FROM ( SELECT ID,
Year,
Month,
Trades,
RowNum = ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Year DESC, Month DESC)
FROM ExampleTable
WHERE Trades > 0
) AS t
WHERE t.RowNum = 1;
If, as in your example, Year and Month are stored as VARCHAR you will need to convert to an INT before ordering:
RowNum = ROW_NUMBER() OVER(PARTITION BY ID
ORDER BY
CAST(Year AS INT) DESC,
CAST(Month AS INT) DESC)
Example on SQL Fiddle
If you are only bothered about records where ID is 1, you can do it simply using TOP:
SELECT TOP 1 ID, Year, Month, Trades
FROM ExampleTable
WHERE ID = 1
AND Trades > 0
ORDER BY CAST(Year AS INT) DESC, CAST(MONTH AS INT) DESC;
Why store "year" and "month" as separate columns? In any case, the basic logic is to combine the two values to get the latest one. This is awkward because you are storing numbers as strings and the months are not zero-padded. But it is not so hard:
select id,
max(year + right('00' + month, 2))
from ExampleTable
group by id;
To separate them out:
select id,
left(max(year + right('00' + month, 2)), 4) as year,
right(max(year + right('00' + month, 2)), 2) as month
from ExampleTable
group by id;
Here is a SQL Fiddle. Note when you use SQL Fiddle that you should set the database to the correct database.
I'm not sure whether I get your question right, but shouldn't the following work?
SELECT TOP 1 year + '-' + month AS Last, trades
FROM ExampleTable
WHERE CAST(trades AS INTEGER) > 0
ORDER BY CAST(year AS integer) DESC, CAST(month AS integer) DESC
SQLFiddle
Try this
SELECT TOP 1 ID, [year], trades,
MAX(Convert(INT,[month])) OVER(PARTITION BY [year]) AS [Month]
FROM ExampleTable
WHERE trades > 0

Get the first occurence of the result in each specified group

I have this query in sql server 2012
select sum(user_number),
sum(media_number),
month_name from (
select TOP 100
count(distinct a.answer_group_guid) as 'user_number',
count(distinct a.media_guid) as 'media_number',
datename(mm,answer_datetime) as 'month_name' ,year(answer_datetime) as 'year'
from
tb_answers as a
left outer join
tb_media as m ON m.user_guid = 'userguid' and m.media_guid=a.media_guid
where
m.user_guid = 'userguid'
group by concat(year(answer_datetime),'',month(answer_datetime)),datename(mm,answer_datetime),year(answer_datetime)
order by year(answer_datetime) desc) as aa
group by month_name,year
order by month_name desc,year desc;
it get this result
Out
user_number media_number month_name
5 1 September
2 1 October
1 1 October
1 1 August
But I need only the first occurence of octuber month
as
user_number media_number month_name
5 1 September
2 1 October
1 1 August
You simply need to use a ranking function like ROW_NUMBER(). Use it to number the records partitioning by month_name, and select only the records which are number 1 in each partition, i.e.
Add this to the select list of your query:
ROW_NUMBER() OVER(PARTITION BY month_name ORDER By XXX) as RowNumber
This will number the rows which have the same month_name with consecutive numbers, starting by 1, and in the order specified by XXX.
NOTE: specify the order in XXX to decide which of the month rows is number one and will be returned by the query
And then, do a select from the resulting query, filtering by RowNumber = 1
SELECT Q.user_number, Q.media_number, Q.month_name
FROM(
-- your query + RowNumber) Q
WHERE Q.RowNumber = 1
NOTE: if you need some ordering in your result, you'll have to move the ORDER BY out of the subselect, and write it beside the WHERE Q.RowNumber=1

SQL: Select Multiple Columns with Max() on calculated values

Real basic: I have table T with following data:
ID StartDate Term (months)
----------------------
1 10/1/2012 12
2 10/1/2012 24
3 12/1/2012 12
I need to know the ID of the row that has the max end date. I've successfully calculated the end date as
select max( DateAdd(month, term, StartDate) from table [this would result in 10/1/2014]
how do i get the ID value and Start Date of the row that contains the max end date?
MS SQL:
SELECT TOP 1 ID, StartDate
FROM T
ORDER BY DateAdd(month, term, StartDate) DESC
MySQL:
SELECT ID, StartDate
FROM T
ORDER BY DateAdd(month, term, StartDate) DESC
LIMIT 1
In case more than one ID has the same extreme "end date" and you need them all, you can try this:
SELECT x.id
FROM (
SELECT id
, RANK ( ) OVER ( ORDER BY DateAdd(month, term, StartDate) DESC) as rn
FROM T
) x
WHERE t.rn = 1