row_number Over Partition - sql-server-2008

I'm using SQL Server 2008 R2. I have table called EmployeePurcheses with the following structure and sample data:
EmployeeID Date Usd
1 2014-11-12 5
1 2014-11-18 9
1 2014-11-18 7
What I am trying to do is to list of work week of this employee's employment in each Date ordered by the Date field. So, the output will look like this:
rn EmployeeID Date WW
1 1 2014-11-12 46
2 1 2014-11-18 47
2 1 2014-11-18 47
I intended to use partitioning the data using the following query but it failed. Thank you, in advance.
select
rn = ROW_NUMBER() over (partition by DATEPART(ww, [Date]) order by
DATEPART(ww, [Date]))
,[EmployeeID ]
,Cast([Date] as date) as [Date]
,DATEPART(ww, [Date]) as WW
FROM EmployeePurcheses
Order by [Date] asc

According to your result you need DENSE_RANK() with no partitioning:
WITH EmployeePurchases AS
(
SELECT * FROM (VALUES
(1, '2014-11-12', 5),
(1, '2014-11-18', 9),
(1, '2014-11-18', 7)) T(EmployeeID, Date, Usd)
)
select
rn = DENSE_RANK() over (order by DATEPART(WW, [Date]))
,[EmployeeID]
,Cast([Date] as date) as [Date]
,DATEPART(ww, [Date]) as WW
FROM EmployeePurchases
Order by [Date] asc

Related

Get active users by month

Using MySQL, I'm trying to get the number of active users I have in any given month. I have a table with ActivationDate and TerminationDate columns, and if the month being counted is after the ActivationDate and TerminationDate is null, then the user is active and should be counted. I would like to summarize these amounts by month. I'm thinking I could just sum each side and calculate the total but breaking that down won't give me a running total. I've tried with window functions, but I don't have enough experience with them to know exactly what I'm doing wrong and I'm not certain how to ask the right question.
So for instance, if I have the following data...
UserId ActivationDate TerminationDate
1 2020-01-01 null
2 2020-01-15 null
3 2020-01-20 2020-01-30
4 2020-02-01 null
5 2020-02-14 2020-02-27
6 2020-02-15 2020-02-28
7 2020-03-02 null
8 2020-03-05 null
9 2020-03-20 2020-03-21
I would like my results to be similar to:
2020-01 2 (there are 2 active users, since one signed up but cancelled before the end of the month)
2020-02 3 (2 from the previous month, plus 1 that signed up this month and is still active)
2020-03 5 (3 from previous, 2 new, 1 cancellation)
You can unpivot, then aggregate and sum. In MySQL 8.0.14 or higher, you can use a lateral join:
select date_format(x.dt, '%Y-%m-01') as dt_month,
sum(sum(cnt)) over(order by date_format(x.dt, '%Y-%m-01')) as cnt_active_users
from mytable t
cross join lateral (
select t.activationdate as dt, 1 as cnt
union all select t.terminationdate, -1
) x
where x.dt is not null
group by dt_month
order by dt_month
In earlier 8.x versions:
select date_format(x.dt, '%Y-%m-01') as dt_month,
sum(sum(cnt)) over(order by date_format(x.dt, '%Y-%m-01')) as cnt_active_users
from (
select activationdate as dt, 1 as cnt from from mytable
union all select terminationdate, -1 from mytable
) x
where x.dt is not null
group by dt_month
order by dt_month
You don't say what version of MySQL. If you're using 8.0, this should work:
create table userdates (
UserId int not null,
ActivationDate date not null,
TerminationDate date null
);
insert into userdates (UserId, ActivationDate, TerminationDate)
values
(1, cast("2020-01-01" as date), null )
, (2, cast("2020-01-15" as date), null )
, (3, cast("2020-01-20" as date), cast("2020-01-30" as date))
, (4, cast("2020-02-01" as date), null )
, (5, cast("2020-02-14" as date), cast("2020-02-27" as date))
, (6, cast("2020-02-15" as date), cast("2020-02-28" as date))
, (7, cast("2020-03-02" as date), null )
, (8, cast("2020-03-05" as date), null )
, (9, cast("2020-03-20" as date), cast("2020-03-21" as date))
, (10, cast("2020-07-20" as date), null)
, (11, cast("2019-09-12" as date), cast("2019-09-14" as date));
WITH RECURSIVE d (dt)
AS (
SELECT cast("2019-01-01" as date)
UNION ALL
SELECT date_add(dt, interval 1 month)
FROM d
WHERE dt < cast("2020-12-01" as date)
)
select d.dt
, count(distinct ud.UserId) as UserCount
from userdates ud
right outer join d on d.dt >= date_format(ud.ActivationDate, '%Y-%m-01')
and (d.dt <= ud.TerminationDate or ud.TerminationDate is null)
group by d.dt;

SQL query to extract the most recent part and anything that is 30 days older than that date.

I am very new to SQL and I need to write a query that selects data for a specific part. However, It should select only the part that is the most recent(given by date) and anything that is only 30 days prior to it. Please consider the table below:
PartID | Part_NAME | DATE
-----------------------------
1 AAA 6/16/2015
2 BBB 6/15/2015
3 AAA 6/11/2015
4 AAA 1/1/2008
I need a query that gives me:
PartID | Part_NAME | DATE
-----------------------------
1 AAA 6/16/2015
3 AAA 6/11/2015
I have tried:
select * from ( select * from sales_table where Part_NAME = 'AAA') where DATE BETWEEN (max(DATE) and (max(DATE)-30))
I have read some articles saying that I cannot use WHERE and functions like max() together and advised me to use group by or having but it didn't work for me as well. Thank you.
IF you want data from the last 30 days of the current day, you can do :
SELECT *
FROM sales_table
WHERE
[DATE] >= DATEADD(DAY, -30,GETDATE())
AND [DATE] <= GETDATE()
AND Part_NAME = 'AAA'
IF you want data from the last 30 days from the last date of sale of each Part_NAME (this will take the max recorded date of sale for each Part_NAME and get the last 30 days records of each one of them.)
SELECT *
FROM (
SELECT *,
MAX([DATE]) OVER(PARTITION BY Part_NAME ORDER BY PartID) AS RecentDate
FROM sales_table
) D
WHERE
[DATE] >= DATEADD(DAY, -30, RecentDate)
AND [DATE] <= RecentDate
AND Part_NAME = 'AAA'
You can accomplish by using datediff and getdate() and a subquery.
SELECT * FROM (
SELECT *,DATEDIFF(DD,[DATE],GETDATE()) AS DAYSBETWEEN FROM sales_table
) AS X
WHERE DAYSBETWEEN <= 30
If you want data from the last 30 days, it would be:
select st.*
from sales_table st join
(select top (1) st2.*
from sales_table st2
order by st2.date desc
) st2
on st2.part_name = st.part_name and
st.date >= dateadd(day, -30, cast(getdate() as date));

How to insert into a table all dates and all months between year 2000 and 2020?

I have created a table called time_range in SQL Server 2008 with columns
date ID, Month ID, year ID
How can I bulk insert all the date, month, year into these columns from year 2000 to 2020? Is there any simple query to do this?
Please help thanks in advance.
From:
1/1/2000 | January |2000
TO :
31/12/2020| December | 2020
You can use recursive CTE to do this:
with cte (dateId)
as (
select cast('2000-01-01' as date)
union all
select dateadd(day, 1, dateId)
from cte
where dateId < cast('2020-12-31' as date)
)
select dateId,
datename(Month, dateId) as monthId,
year(dateId) as yearId
from cte
option (maxrecursion 0); -- to remove the recursion limit
You can use this to do the insert into other table

interval by 4 using sql - Mysql

I've a table and i want that data is interval by 4 or, when i'm using modulo the record is not that i expected, PFB `
SELECT (DATE_FORMAT(subscribed_from, '%Y-%m')) AS date_ FROM subscription
WHERE operator = 'tim'
AND DATE_FORMAT(subscribed_from, '%Y-%m-%d') BETWEEN '2013-01-01' AND '2014-12-31'
GROUP BY (DATE_FORMAT(subscribed_from, '%Y-%m'));
it will show record like this
2013-01
2013-02
2013-03
2013-04
2013-05
2013-06
2013-07
2013-08
2013-09
i want take only data interval by 4, this below is record that i expected.
2013-01
2013-05
2013-09
2014-02
and also for interval by 2, this below record is that i expected
2013-01
2013-03
2013-05
2013-07
2013-09
if i using modulo % 2 it will start from 2013-01 and jump by 2, but the problem if the where range i want to start from 2013-02, 02 it self not showing on the result. so if the where clause the month start from 2 it will given the interval such as 2,4,6,8,10,12
SELECT date_, SUM(the_metric_you_want_to_aggregate)
FROM (
SELECT 4*FLOOR(
(DATE_FORMAT(subscribed_from, '%Y%m') - 201301)
/4) AS date_,
the_metric_you_want_to_aggregate
FROM subscription
WHERE operator = 'tim'
AND subscribed_from BETWEEN 20130101000000 AND 201412315959
) AS ilv
GROUP BY date_
(where 201301 is the year/month start of the range you are selecting by - assuming that is the reference for the 4-month aggregation)
Note that enclosing column references in functions (...DATE_FORMAT(subscribed_from, '%Y-%m-%d') BETWEEN...) prevents the use of indexes.
You have to use variables. Here is sample for interval by 4.
SET #row_number:=0;
SELECT date_ from (
SELECT (DATE_FORMAT(subscribed_from, '%Y-%m')) AS date_,#row_number:=#row_number+1 FROM subscription
WHERE operator = 'tim' AND DATE_FORMAT(subscribed_from, '%Y-%m-%d') BETWEEN '2013-01-01' AND '2014-12-31'
GROUP BY (DATE_FORMAT(subscribed_from, '%Y-%m'))
) as tbl where #row_number % 4=0;
let says i'm using this method to generate the intevals, but i want the start number is from my input, let says it start from 4 and if the condition put %4 should be the output is 4, 8 ,12 ....
enter code here
SET #row:=0;
SELECT *
FROM (
SELECT
#row := #row +1 AS rownum
FROM (
SELECT #row) r, subscription
) ranked
WHERE rownum %4 = 1

Cumulative SUM SQL Server 2008

I have table
Year Month Week Amount
-------------------------------------
2014 1 1 25501000,00
2014 1 2 118852000,00
2014 1 3 135764000,00
2014 1 4 153967000,00
2014 1 5 157648000,00
And I need select with one more row, that will be cumulative SUM of amount in each week:
Year Month Week ApvdAmtWeek SUMamount
---------------------------------------------------
2014 1 1 25501000,00 x1
2014 1 2 118852000,00 x1+x2
2014 1 3 135764000,00 x1+x2+x3
2014 1 4 153967000,00 x1+x2+x3+x4
2014 1 5 157648000,00 x1+x2+x3+x4+x5
Thank you for any help.
This may help you.
DECLARE #TAB TABLE (YEAR INT, MONTH INT, WEEK INT,AMOUNT BIGINT)
INSERT INTO #TAB VALUES
(2014,1,1,2550100000) ,
(2014,1,2,11885200000),
(2014,1,3,13576400000),
(2014,1,4,15396700000),
(2014,1,5,15764800000)
--Query:
SELECT Year,Month,Week,SUM(AMOUNT) ApvdAmtWeek FROM (
SELECT B.YEAR,B.MONTH,B.WEEK,A.AMOUNT
FROM #TAB A,#TAB B
WHERE A.WEEK <= B.WEEK) LU
GROUP BY YEAR,MONTH,WEEK
--Result:
One way, not pretty as there is no ID:
;with T as (
select row_number() over (order by year, Month, Week) rn, Year, Month, Week, Amount
from thetable
)
select T.rn, T.Year, T.Month, T.Week, sum(T2.Amount) from T
inner join (select
rn, Year, Month, Week, Amount from T
) T2 on T.rn >= T2.rn
group by T.rn, T.Year, T.Month, T.Week
order by T.rn