SQL Server:按周格式分组W 22/09-28/09

时间:2018-10-01 01:39:04

标签: sql sql-server date format

我需要执行以下操作:

Year   |   Weekno   |     Weekrange       |    No_Users
-------+------------+---------------------+-------------
2018   |     29     |   W 22/09 - 28/09   |     68,574
2018   |     28     |   W 15/09 - 21/09   |     57,452
....

根据以下数据:

Login_time    |    User
--------------+------------------   
2018-09-27    |  alex9172
2018-09-26    |  christinelane
2018-09-26    |  alex9172
2018-09-26    |  abcded
2018-09-25    |  nqohs
2018-09-25    |  abcded
2018-09-25    |  alex9172
2018-09-25    |  owscjwo91
....

所以想出了一年和一周的时间,我可以使用

group by datepart(week, Login_date), datepart(year, login_date)

但是在周末,我被困住了。

请帮助我,谢谢。

3 个答案:

答案 0 :(得分:1)

请尝试以下查询:

    select yr, wk, concat('W ',FORMAT(min(login_time), 'dd/MM', 'en-US' ),' - W ',FORMAT(max(login_time), 'dd/MM', 'en-US' )) as weekrange, 
    count(user) as totaluser
    from
    (
    select year(Login_time) as yr,datepart(isowk, Login_time) as wk, Login_time,user
    from tablename
    )A 
    group by yr, wk

答案 1 :(得分:0)

嗨,经过一段时间的挣扎,我终于找到了解决方法:

   SELECT
     datepart(year, login_time) as year
    ,datepart(week, login_time) as weekno
    ,'W ' + format(DATEADD(DAY, 2 - DATEPART(WEEKDAY, login_time), login_time), 'dd'+'/'+'MM') + ' - ' + format(DATEADD(DAY, 8 - DATEPART(WEEKDAY, login_time), login_time), 'dd'+'/'+'MM') as weekrange
    ,COUNT(DISTINCT User) as No_Users
   FROM mytable
   GROUP BY datepart(year, login_time)
            ,datepart(week, login_time)
            ,'W ' + format(DATEADD(DAY, 2 - DATEPART(WEEKDAY, login_time), login_time), 'dd'+'/'+'MM') + ' - ' + format(DATEADD(DAY, 8 - DATEPART(WEEKDAY, login_time), login_time), 'dd'+'/'+'MM')

非常感谢Satyaprakash Samantaray:https://www.c-sharpcorner.com/blogs/get-week-start-date-week-end-date-using-sql-server

答案 2 :(得分:0)

我不能对性能做出任何保证,但我相信它每次都会给出正确的答案。

create table UserLogin ( [User] nvarchar(50),
                         Login_Time datetime2 )

insert into UserLogin ( [User], Login_Time ) values
( 'Bart',  '2018-12-31T12:13:14.888' ),
( 'Mary',  '2019-01-06T09:10:11.876' ),
( 'Fred',  '2018-12-31T21:22:23.456' ),
( 'Fred',  '2019-01-01T07:08:09.101' ),
( 'Fred',  '2018-09-17T13:14:15.616' ),
( 'Wilma', '2018-09-23T11:12:13.141' ),
( 'Betty', '2018-11-11T14:41:14.444' )

;with

-- Using DATEPART(WEEK,... has a problem. When called on two dates 
-- in the same week, it can give different results.
-- For example, 31-Dec-2018 and 01-Jan-2019 are in the same week, 
-- but DATEPART(WEEK,... returns 53 and 1.
-- To solve this, we'll use ISO_WEEK instead.
-- ISO defines week 1 of a year as the seven days starting on a Monday 
-- that contain the first Thursday of the year.
-- This means that week 1 can begin in the previous year.
-- Calling DATEPART(ISO_WEEK,... on 31-Dec-2018 and 01-Jan-2019 both return 1.
U as
( select [User],
         Login_Time,
         DatePart(ISO_WEEK,Login_Time)as [Week],
         Year(Login_Time)as [Year] 
         from UserLogin ),

-- For both 31-Dec-2018 and 01-Jan-2019, we want the 
-- Year to be 2019 and the Week to be 1.
-- So when we have ISO week 1, and a date near the end of the year, 
-- we want to use the following year.
V as
( select [User],
         [Week],
         case when [Week]=1 and Month(Login_Time)=12 
           then [Year]+1 
           else [Year] 
         end as [Year] 
         from U ),

-- Count the distinct users in each time period
A as
( select [Year],
         [Week],
         count(distinct [User])as No_Users 
         from V 
         group by [Year],[Week] ),

-- This is January 1st of year 0001, the earliest date that SQL Server 
-- can handle. We'll be using it shortly.
Z as
( select cast('0001-01-01T00:00:00.000'as datetime2)as DayZero ),

-- To get the first day of the year, 
-- add that many years, subtract 1, to 01-Jan-0001.
F as
( select No_Users, 
         DATEADD(year,[Year]-1,DayZero)as FirstDayOfYear,[Year], 
         [Week] 
         from A, Z ),

-- What day of the week is the first day of the year?  
-- By counting the days from 01-Jan-0001 we bypass 
-- any confusion caused by different values of @@DATEFIRST,
-- or negative numbers.  Divide by 7 and keep the remainder. 
-- The result is 0 for Monday, 1 for Tuesday and so on.
D as
( select No_Users, 
         FirstDayOfYear,
         DATEDIFF(day,DayZero,FirstDayOfYear)%7 as DayOfWeekOfFirstDay,
         [Year],
         [Week] 
         from Z, F ),

-- Now we work out the date of the Monday of the week 1.
-- When the first day of the year is a Monday (0), 
-- we just keep that day.
-- When it is Tuesday (1), we subtract 1 day. 
-- For Wednesday(2), we subtract 2 days.
-- And for Thursday (3), we subtract 3 days.
-- If the first day of the year is Friday (4), we need to add 3 days.
-- For Saturday (5) we add 2 days, 
-- and for Sunday (6) we add 1 day.
-- The expression   ( 10 - X ) % 7 - 3  
-- gives us the number of days to add.
T as
( select No_Users,
         DayOfWeekOfFirstDay, 
         DATEADD(day,(10-DayOfWeekOfFirstDay)%7-3,FirstDayOfYear)
           as MondayWeekOne,
         [Year],
         [Week] from D ),

-- That gives us the Monday of the first week of the year.
-- Now we need to find the Monday of the week we're looking for.
W as
( select No_Users, 
         DATEADD(day,7*([Week]-1),MondayWeekOne)as MondayOfWeek,
         [Year],
         [Week] from T ),

-- Given the Monday that begins that week, 
-- find the Sunday that ends that week.
S as
( select No_Users, 
         MondayOfWeek, 
         DATEADD(day,6,MondayOfWeek)as SundayOfWeek,
         [Year],
         [Week] from W )

-- Format and sort to taste.
select [Year],
       [Week], 
       'W ' + format(MondayOfWeek, 'dd/MM') 
            + ' - ' 
            + format(SundayOfWeek, 'dd/MM') as WeekRange,
       No_Users
       from S
       order by [Year],[Week]

结果是:

Year        Week        WeekRange       No_Users
----------- ----------- --------------- --------
2018        38          W 17/09 - 23/09    2                                                                                                                                                                                                                                             
2018        45          W 05/11 - 11/11    1 
2019        1           W 31/12 - 06/01    3