简体   繁体   中英

TSQL - how to determine first and last days of the week for a given week number

I have data in the below format:

TrDate:2018-01-01 00:00:00.000 | Amount: 10.00
TrDate:2018-01-02 00:00:00.000 | Amount: 20.00

And I want to consolidate data at weekly level:

Week:1 | Start Date: | End Date:| Total Amount

I have query which consolidates data at weekly but I do not know how to get the start and end dates for the respective week. This was my query:

 SELECT      DATEPART(wk, trdate)     weekno,
     round(SUM(amount),2) AS total_amount
 FROM        <table>
 GROUP BY    DATEPART(wk, trdate);

FYI: Week starts from Sunday and Ends on Saturday.

Try this:

select weekno, weekStart, weekEnd,   round(SUM(amount),2) AS total_amount from 
(
  SELECT      
    DATEPART(wk, trdate)     weekno,
    DATEADD(dd, -(DATEPART(dw, trdate)-1), trdate) [WeekStart],
    DATEADD(dd, 7-(DATEPART(dw, trdate)), trdate) [WeekEnd],
    amount
  from table1
)t
group by Weekno, weekstart, weekend

You can use this expression to find the previous Sunday for a given date (it works regardless of @@DATEFIRST setting):

SELECT DATEADD(DAY, -CASE DATENAME(WEEKDAY, <date>)
    WHEN 'SUNDAY'    THEN 0
    WHEN 'MONDAY'    THEN 1
    WHEN 'TUESDAY'   THEN 2
    WHEN 'WEDNESDAY' THEN 3
    WHEN 'THURSDAY'  THEN 4
    WHEN 'FRIDAY'    THEN 5
    WHEN 'SATURDAY'  THEN 6
END, <date>) AS weekstart

You can use it in your query as follows:

SELECT weekno, total_amount, DATEADD(DAY, -CASE DATENAME(WEEKDAY, refdate)
        WHEN 'SUNDAY'    THEN 0
        WHEN 'MONDAY'    THEN 1
        WHEN 'TUESDAY'   THEN 2
        WHEN 'WEDNESDAY' THEN 3
        WHEN 'THURSDAY'  THEN 4
        WHEN 'FRIDAY'    THEN 5
        WHEN 'SATURDAY'  THEN 6
    END, refdate) AS weekstart, DATEADD(DAY, CASE DATENAME(WEEKDAY, refdate)
        WHEN 'SUNDAY'    THEN 6
        WHEN 'MONDAY'    THEN 5
        WHEN 'TUESDAY'   THEN 4
        WHEN 'WEDNESDAY' THEN 3
        WHEN 'THURSDAY'  THEN 2
        WHEN 'FRIDAY'    THEN 1
        WHEN 'SATURDAY'  THEN 0
    END, refdate) AS weekend
FROM (
    SELECT DATEPART(wk, trdate) weekno
         , ROUND(SUM(amount),2) AS total_amount
         , MIN(trdate) AS refdate
    FROM t
    GROUP BY DATEPART(wk, trdate)
) AS cte

Solution

 SELECT 
    weekno,
    convert(varchar(10),DATEADD(dd, 1 - DATEPART(dw, date1), date1),111) startdate,
    convert(varchar(10),DATEADD(dd, 7 - DATEPART(dw, date2), date2),111) enddate,
    total_amount
    from
    (
          SELECT  
            DATEPART(wk, trdate) weekno,
            cast(min(trdate) as date) as date1, 
            cast(max(trdate) as date) as date2, 
            round(SUM(amount),2) AS total_amount
         FROM        <table>
         GROUP BY    DATEPART(wk, trdate)
     ) t

produces output like this (note: I added some data of my own to test a couple of edge cases).

在此处输入图片说明

Notes

  1. It wasn't clear in the question whether datetime values can have a time component other than midnight. My answer assumes there might be non-midnight times.
  2. The weekno values might seem odd at the beginning and/or end of the year, but the OP's query yields the same value for weekno for those edge cases.
  3. Neither OP's query, nor any of the answers so far restrict the data by year, and they group only by week#. Thus if data from multiple years are included, you will still only get 53 rows, and each row will contain the aggregate data from all years in the data for that week. The start and end dates will then overlap and look strange. You could add additional grouping by year to further divide this, but the simplest fix would be to restrict the data to a single year, with a WHERE clause just prior to the GROUP BY clause, eg:

      WHERE trdate >= '2018/01/01' and trdate < '2019/01/01' 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM