SQL query to find out number of days in a week a user visited - sql

I'd like to find out how many days in a week users have visited my site. For example, 1 day in a week, 2 days in a week, every day of the week (7).
I imagine the easiest way of doing this would be to set the date range and find out the number of days within that range (option 1). However, ideally I'd like the code to understand a week so I can run a number of weeks in one query (option 2). I'd like the users to be unique for each number of days (ie those who have visited 2 days have also visited 1 day but would only be counted in the 2 days row)
In my database (using SQLWorkbench64) I have user ids (id) and date (dt)
I'm relatively new to SQL so any help would be very much appreciated!!
Expected results (based on total users = 5540):
Option 1:
Number of Days Users
1 2000
2 1400
3 1000
4 700
5 300
6 100
7 40
Option 2:
Week Commencing Number of Days Users
06/05/2019 1 2000
06/05/2019 2 1400
06/05/2019 3 1000
06/05/2019 4 700
06/05/2019 5 300
06/05/2019 6 100
06/05/2019 7 40

You can find visitor count between a date range with below script. Its also consider if a visitor visits multi days in the given date range, s/he will be counted for the latest date only from the range-
Note: Dates are used as sample in the query.
SELECT date,COUNT(id)
FROM
(
SELECT id,max(date) date
FROM your_table
WHERE date BETWEEN '04/21/2019' AND '04/22/2019'
GROUP BY ID
)A
GROUP BY date

You can find the Monday of the week of a date and then group by that. After you have the week day there is a series of group by. Here is how I did this:
DECLARE #table TABLE
(
id INT,
date DATETIME,
MondayOfWeek DATETIME
)
DECLARE #info TABLE
(
CommencingWeek DATETIME,
NumberOfDays INT,
Users INT
)
INSERT INTO #table (id,date) VALUES
(1,'04/15/2019'), (2,'07/21/2018'), (3,'04/16/2019'), (4,'04/16/2018'), (1,'04/16/2019'), (2,'04/17/2019')
UPDATE #table
SET MondayOfWeek = CONVERT(varchar(50), (DATEADD(dd, ##DATEFIRST - DATEPART(dw, date) - 6, date)), 101)
INSERT INTO #info (CommencingWeek,NumberOfDays)
SELECT MondayOfWeek, NumberDaysInWeek FROM
(
SELECT id,MondayOfWeek,COUNT(*) AS NumberDaysInWeek FROM #table
GROUP BY id,MondayOfWeek
) T1
SELECT CommencingWeek,NumberOfDays,COUNT(*) AS Users FROM #info
GROUP BY CommencingWeek,NumberOfDays
ORDER BY CommencingWeek DESC
Here is the output from my query:
CommencingWeek NumberOfDays Users
2019-04-14 00:00:00.000 1 2
2019-04-14 00:00:00.000 2 1
2018-07-15 00:00:00.000 1 1
2018-04-15 00:00:00.000 1 1

Related

Query to find SUM based on week

I have a table like date , sales , region
date
Sales
Region
11/02/2021
20
1
12/02/2021
23
1
13/02/2021
30
2
14/02/2021
50
2
15/02/2021
10
3
16/02/2021
10
3
How to extract sum of sales per region based on weeks (Week starting from Monday to Sunday)
You need to select the week before grouping.
This should work for you:
SELECT DATEPART(week, date) AS Week,
FROM table
GROUP BY DATEPART(week, RegistrationDate);

T-SQL filtering records based on dates and time difference with other records

I have a table for which I have to perform a rather complex filter: first a filter by date is applied, but then records from the previous and next days should be included if their time difference does not exceed 8 hours compared to its prev or next record (depending if the date is less or greater than filter date).
For those adjacent days the selection should stop at the first record that does not satisfy this condition.
This is how my raw data looks like:
Id
Desc
EntryDate
1
Event type 1
2021-03-12 21:55:00.000
2
Event type 1
2021-03-12 01:10:00.000
3
Event type 1
2021-03-11 20:17:00.000
4
Event type 1
2021-03-11 05:04:00.000
5
Event type 1
2021-03-10 23:58:00.000
6
Event type 1
2021-03-10 11:01:00.000
7
Event type 1
2021-03-10 10:00:00.000
In this example set, if my filter date is '2021-03-11', my expected result set should be all records from that day plus adjacent records from 03-12 and 03-10 that satisfy the 8 hours condition. Note how record with Id 7 is not be included because record with Id 6 does not comply:
Id
EntryDate
2
2021-03-12 01:10:00.000
3
2021-03-11 20:17:00.000
4
2021-03-11 05:04:00.000
5
2021-03-10 23:58:00.000
Need advice how to write this complex query
This is a variant of gaps-and-islands. Define the difference . . . and then groups based on the differences:
with e as (
select t.*
from (select t.*,
sum(case when prev_entrydate > dateadd(hour, -8, entrydate) then 0 else 1 end) over (order by entrydate) as grp
from (select t.*,
lag(entrydate) over (order by entrydate) as prev_entrydate
from t
) t
)
select e.*
from e.*
where e.grp in (select e2.grp
from t e2
where date(e2.entrydate) = #filterdate
);
Note: I'm not sure exactly how filter date is applied. This assumes that it is any events on the entire day, which means that there might be multiple groups. If there is only one group (say the first group on the day), the query can be simplified a bit from a performance perspective.
declare #DateTime datetime = '2021-03-11'
select *
from t
where t.EntryDate between DATEADD(hour , -8 , #DateTime) and DATEADD(hour , 32 , #DateTime)

creating weekly buckets in date column in sql

How can i create weekly buckets for a date column.
My data looks like :
ID LOC DATE Amount
1 AAA 21-07-2015 3000
2 AAA 22-07-2015 1000
3 AAA 23-07-2015 0
4 AAA 27-07-2015 300
5 AAA 29-07-2015 700
I also have a Financial Year Calendar file containing the week start and end ranges and which week each bucket falls on.It looks like
Year WeekStart WeekEnd Week
2015 20-07-2015 26-07-2015 1
2015 27-07-2015 02-08-2015 2
so on till 2020...
The task here is I have to group all the line items in A table fall under each bucket and find the amount value per week.
Output:
ID LOC WEEk Amount
1 AAA 1 4000
2 AAA 2 1000
Not sure how to start the process itself or how to link these both files.Kindly need your help.
You need here Correlated Subqueries https://technet.microsoft.com/en-us/library/ms187638(v=sql.105).aspx. Let's assume data is in table data, calendar in table calendar. Then your query will look like
select
loc, week, sum(amount)
from
(select
(select top 1 week from calendar t1 where t1.WeekStart <= t2.date and t2.date <= t1.WeekEnd) as week,
loc,
amount
from
data t2) as subsel1
group by
loc, week

SQL Query to provide a count of jobs that were open grouped by week, month, year for the last 12 months

Given the following data:
Job CreatedDate ClosedDate
ID6 2014-06-04 01:51:47.060 NULL
ID7 2014-06-05 00:25:35.187 NULL
ID43 2014-06-16 05:17:18.803 2014-06-26 15:00:15.190
ID72 2014-06-20 04:00:07.733 2014-06-20 04:12:18.770
ID84 2014-06-27 16:01:18.953 NULL
ID74 2014-06-20 04:05:42.843 NULL
ID68 2014-06-20 03:46:52.653 2014-06-20 03:52:47.540
ID88 2014-07-03 03:47:55.407 NULL
ID64 2014-06-19 07:29:37.060 NULL
ID104 2014-07-08 02:59:58.337 2014-07-15 15:00:15.543
ID106 2014-07-08 03:02:29.710 2014-07-16 11:04:19.230
ID130 2014-07-10 04:30:20.900 NULL
ID132 2014-07-10 04:32:20.243 NULL
ID150 2014-07-15 20:59:06.077 2014-07-15 21:10:19.490
.
.
.
Etc.
I need to write a query that will group records by week, month, and year. A count of the number of records that were in an Open state at the end of each week (Sunday) needs to be returned.
The difficulty arises in determining if a job was in an Open state at the end of a particular week. I imagine the logic goes something like this: A job was open if the CreatedDate is less than or equal to the end of the week and the ClosedDate is after the end of the week or ClosedDate is NULL. A job can remain open over many weeks.
The output should look as follows.
Week Month Year Count
23 6 2014 80
24 6 2014 36
25 6 2014 71
26 6 2014 0
27 7 2014 25
28 7 2014 180
So, at the end of week 23 there were 80 jobs that were still open. Where a week has no records the count should return 0. Only records that were created 12 months from the time the query is executed should be returned. The query is executed every week and used to build a rolling 12 month report. I am using Microsoft SQL Server 2012.
I’ll give an example:
At the beginning of week 1 there are no jobs in the table. During week 1, 50 jobs are opened and 30 are closed which means that 20 are in an Open state at the end of the week.
During week 2, a further 50 jobs are opened and 40 are closed which means that 30 are in an Open state (when you add the 20 from last week and the 10 from this week) at the end of the week. Some of the jobs closed in week 2 were created in week 1 and some of the open jobs are still from week 1.
During week 3, a further 50 jobs are opened and 40 are closed which means that 40 are in an Open state at the end of the week. Some of the jobs closed in week 3 were created in weeks 1 and 2 and some of the open jobs are still from weeks 1 and 2.
And so on for a 12 month period.
When I run the query at the end of week 3 I want to know that at the end of week 1 there were 20 jobs open and at the end of week 2 there were 30 and at the end of week 3 there were 40. You can’t rely on the ClosedDate being NULL because even thought it was at the end of week 1 it may have been closed during week 3 and now has a ClosedDate. As I mentioned above, I think the logic that needs to be used is: A job was in the Open state at the end of a week if the CreatedDate is less than or equal to the end of the week and the ClosedDate is after the end of the week or ClosedDate is NULL.
So, at the end of week 3, when the query is run, the data that I would like to receive would look like:
Week Month Year Count
1 1 2014 20
2 1 2014 30
3 1 2014 40
A manual way of achieving what I need is to run a simple query at the end of each week that counts the number of jobs that have a ClosedDate of NULL. I then manually enter the week, month, year, and count into a table and use that table as a source for reporting. I was hoping that a more automated process could be achieved.
Thanks in advance
Hope this is what you are looking for..
DECLARE #S INT = (SELECT CAST(CAST(MIN([CREATEDDATE]) AS DATETIME) AS INT) FROM [DBO].[YOURTABLE] WHERE [CLOSEDDATE] IS NULL)
DECLARE #E INT = (SELECT CAST(CAST(MAX([CREATEDDATE]) AS DATETIME) AS INT) FROM [DBO].[YOURTABLE] WHERE [CLOSEDDATE] IS NULL)
DECLARE #TAB TABLE (ID INT PRIMARY KEY IDENTITY(1,1), DT DATETIME)
WHILE #S <= #E
BEGIN
INSERT INTO #TAB
SELECT CAST(#S AS DATETIME)
SET #S = #S + 1
END
SELECT MAIN.WEEK,Main.MONTH,Main.YEAR,
LU.COUNT
FROM (
SELECT DATEPART(YEAR,DT) YEAR,
DATEPART(MONTH,DT) MONTH,
DATEPART(WEEK,DT) WEEK
FROM #TAB
GROUP BY DATEPART(YEAR,DT),
DATEPART(MONTH,DT),
DATEPART(WEEK,DT)) MAIN
LEFT JOIN
(
SELECT DATEPART(YEAR,[CREATEDDATE]) YEAR,
DATEPART(MONTH,[CREATEDDATE]) MONTH,
DATEPART(WEEK,[CREATEDDATE]) WEEK,
COUNT(*) COUNT
FROM [DBO].[YOURTABLE]
WHERE [CLOSEDDATE] IS NULL
GROUP BY DATEPART(YEAR,[CREATEDDATE]),
DATEPART(MONTH,[CREATEDDATE]) ,
DATEPART(WEEK,[CREATEDDATE])) LU
ON MAIN.YEAR = LU.YEAR
AND MAIN.MONTH = LU.MONTH
AND MAIN.WEEK = LU.WEEK
ORDER BY MAIN.YEAR,
MAIN.MONTH,
MAIN.WEEK

How to aggregate 7 days in SQL

I was trying to aggregate a 7 days data for FY13 (starts on 10/1/2012 and ends on 9/30/2013) in SQL Server but so far no luck yet. Could someone please take a look. Below is my example data.
DATE BREAD MILK
10/1/12 1 3
10/2/12 2 4
10/3/12 2 3
10/4/12 0 4
10/5/12 4 0
10/6/12 2 1
10/7/12 1 3
10/8/12 2 4
10/9/12 2 3
10/10/12 0 4
10/11/12 4 0
10/12/12 2 1
10/13/12 2 1
So, my desired output would be like:
DATE BREAD MILK
10/1/12 1 3
10/2/12 2 4
10/3/12 2 3
10/4/12 0 4
10/5/12 4 0
10/6/12 2 1
Total 11 15
10/7/12 1 3
10/8/12 2 4
10/9/12 2 3
10/10/12 0 4
10/11/12 4 0
10/12/12 2 1
10/13/12 2 1
Total 13 16
--------through 9/30/2013
Please note, since FY13 starts on 10/1/2012 and ends on 9/30/2012, the first week of FY13 is 6 days instead of 7 days.
I am using SQL server 2008.
You could add a new computed column for the date values to group them by week and sum the other columns, something like this:
SELECT DATEPART(ww, DATEADD(d,-2,[DATE])) AS WEEK_NO,
SUM(Bread) AS Bread_Total, SUM(Milk) as Milk_Total
FROM YOUR_TABLE
GROUP BY DATEPART(ww, DATEADD(d,-2,[DATE]))
Note: I used DATEADD and subtracted 2 days to set the first day of the week to Monday based on your dates. You can modify this if required.
Use option with GROUP BY ROLLUP operator
SELECT CASE WHEN DATE IS NULL THEN 'Total' ELSE CONVERT(nvarchar(10), DATE, 101) END AS DATE,
SUM(BREAD) AS BREAD, SUM(MILK) AS MILK
FROM dbo.test54
GROUP BY ROLLUP(DATE),(DATENAME(week, DATE))
Demo on SQLFiddle
Result:
DATE BREAD MILK
10/01/2012 1 3
10/02/2012 2 4
10/03/2012 2 3
10/04/2012 0 4
10/05/2012 4 0
10/06/2012 2 1
Total 11 15
10/07/2012 1 3
10/08/2012 4 7
10/10/2012 0 4
10/11/2012 4 0
10/12/2012 2 1
10/13/2012 2 1
Total 13 16
You are looking for a rollup. In this case, you will need at least one more column to group by to do your rollup on, the easiest way to do that is to add a computed column that groups them into weeks by date.
Take a lookg at: Summarizing Data Using ROLLUP
Here is the general idea of how it could be done:
You need a derived column for each row to determine which fiscal week that record belongs to. In general you could subtract that record's date from 10/1, get the number of days that have elapsed, divide by 7, and floor the result.
Then you can GROUP BY that derived column and use the SUM aggregate function.
The biggest wrinkle is that 6 day week you start with. You may have to add some logic to make sure that the weeks start on Sunday or whatever day you use but this should get you started.
The WITH ROLLUP suggestions above can help; you'll need to save the data and transform it as you need.
The biggest thing you'll need to be able to do is identify your weeks properly. If you don't have those loaded into tables already so you can identify them, you can build them on the fly. Here's one way to do that:
CREATE TABLE #fy (fyear int, fstart datetime, fend datetime);
CREATE TABLE #fylist(fyyear int, fydate DATETIME, fyweek int);
INSERT INTO #fy
SELECT 2012, '2011-10-01', '2012-09-30'
UNION ALL
SELECT 2013, '2012-10-01', '2013-09-30';
INSERT INTO #fylist
( fyyear, fydate )
SELECT fyear, DATEADD(DAY, Number, DATEADD(DAY, -1, fy.fstart)) AS fydate
FROM Common.NUMBERS
CROSS APPLY (SELECT * FROM #fy WHERE fyear = 2013) fy
WHERE fy.fend >= DATEADD(DAY, Number, DATEADD(DAY, -1, fy.fstart));
WITH weekcalc AS
(
SELECT DISTINCT DATEPART(YEAR, fydate) yr, DATEPART(week, fydate) dt
FROM #fylist
),
ridcalc AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY yr, dt) AS rid, yr, dt
FROM weekcalc
)
UPDATE #fylist
SET fyweek = rid
FROM #fylist
JOIN ridcalc
ON DATEPART(YEAR, fydate) = yr
AND DATEPART(week, fydate) = dt;
SELECT list.fyyear, list.fyweek, p.[date], COUNT(bread) AS Bread, COUNT(Milk) AS Milk
FROM products p
JOIN #fylist list
ON p.[date] = list.fydate
GROUP BY list.fyyear, list.fyweek, p.[date] WITH ROLLUP;
The Common.Numbers reference above is a simple numbers table that I use for this sort of thing (goes from 1 to 1M). You could also build that on the fly as needed.