Home > Mobile >  Calculate and find the second day of the week in SQL
Calculate and find the second day of the week in SQL

Time:10-14

Let's say I have data like this

CustomerID Trans_week first
C001 36 36
C001 37 36
C001 39 36
C002 36 36
C002 37 36
C002 38 36
C002 39 36
C003 36 36
C003 40 36
C004 36 36
C004 39 36

But I'm unable to find the second transaction based on Trans_week. I wish for the result to look like this:

CustomerID Trans_week first second
C001 36 36 37
C001 37 36 37
C001 39 36 37
C002 36 36 37
C002 37 36 37
C002 38 36 37
C002 39 36 37
C003 36 36 40
C003 40 36 40
C004 36 36 39
C004 39 36 39

My query:

CREATE TABLE trydata
(
    CustomerID CHAR(7) not null,
    CustTrans date,
    CustSales int,
)
insert into trydata(CustomerID,CustSales,CustTrans)
    values('C001',34,'2022-09-03'),('C002',23,'2022-09-02'),('C003',132,'2022-09-03'),
    ('C004',95,'2022-09-02'),('C002',68,'2022-09-08'),('C001',54,'2022-09-05'),
    ('C002',34,'2022-09-11'),('C002',98,'2022-09-23'),('C004',34,'2022-09-19'),
    ('C001',30,'2022-09-18'),('C003',34,'2022-09-26');

SELECT m.CustomerID, m.Trans_week, n.first as first
FROM (
    SELECT CustomerID,DATEPART(week,CustTrans) AS Trans_week
    FROM trydata
    GROUP BY CustomerID,DATEPART(week,CustTrans)
) m, (
    SELECT CustomerID,min(DATEPART(week,CustTrans)) AS first
    FROM trydata
    GROUP BY CustomerID
) n
WHERE m.CustomerID = n.CustomerID;

CodePudding user response:

Your request seem unclear to me. We will refactor code after we clear this out.

Why Customer C001 has first row 36 if trans week is 39 in your desired output ?

This will give you Min,Max for each customerID row

SELECT CustomerID,DATEPART(week,CustTrans) TransWeek,
  (select MIN(DATEPART(week,CustTrans)) 
    from trydata c 
    where c.CustomerID = trydata.CustomerID)    AS FirstWeek,
  (select MAX(DATEPART(week,CustTrans)) 
    from trydata c 
    where c.CustomerID = trydata.CustomerID)    AS SecondWeek
FROM trydata
Order by CustomerID

And this will give you Min, and higher than Min for each customerID

SELECT *, isnull((select TOP 1 (DATEPART(week,CustTrans))   
                from trydata c 
                    where c.CustomerID = SRC.CustomerID AND DATEPART(week,C.CustTrans) > SRC.TransWeek 
                    ORDER BY DATEPART(week,C.CustTrans) ),'0')  AS SecondWeek 
FROM ( 
    SELECT CustomerID,DATEPART(week,CustTrans) TransWeek,
      (select MIN(DATEPART(week,CustTrans)) from trydata c where c.CustomerID = trydata.CustomerID) AS FirstWeek
    FROM trydata
) SRC

But none of those answers doesn't match your requested output.

Also this one for me , make more sense, if you want to get Min,Max (Top,Last) order week for each Customer

SELECT CustomerID,
  (select MIN(DATEPART(week,CustTrans)) 
    from trydata c 
    where c.CustomerID = trydata.CustomerID)    AS FirstWeek,
  (select MAX(DATEPART(week,CustTrans)) 
    from trydata c 
    where c.CustomerID = trydata.CustomerID)    AS SecondWeek
FROM trydata
Group by CustomerID

CodePudding user response:

You may use ROW_NUMBER() function -inside a subquery- to get the first and second transaction dates for a customer, then use conditional MAX window function on the results of that subquery.

SELECT CustomerID, DATEPART(week,CustTrans) AS Trans_week,
       DATEPART(week, MAX(CASE rn WHEN 1 THEN CustTrans END) OVER (PARTITION BY CustomerID)) first,
       DATEPART(week, MAX(CASE rn WHEN 2 THEN CustTrans END) OVER (PARTITION BY CustomerID)) second
FROM
  (
    SELECT *,
      ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY CustTrans) rn
    FROM trydata
  ) T
ORDER BY CustomerID, Trans_week

See a demo on SQL Server.

As you requested in the comments, if you want to select only one row per customer that showing the first and second weeks, use the following query:

SELECT DISTINCT CustomerID,
       DATEPART(week, MAX(CASE rn WHEN 1 THEN CustTrans END) OVER (PARTITION BY CustomerID)) first,
       DATEPART(week, MAX(CASE rn WHEN 2 THEN CustTrans END) OVER (PARTITION BY CustomerID)) second
FROM
  (
    SELECT *,
      ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY CustTrans) rn
    FROM trydata
  ) T
WHERE rn <= 2
ORDER BY CustomerID

See a demo.

  • Related