sqlms-access

Select only positive values between 2 dates as a calculated column


I have a table that has NAMES, DATES and PRICE columns. I'm running a query against that table to have a summary based on Name and show 2 totals. The values in PRICE are positive and negative.

I currently have 2 columns in the query CurTotal and CurPay that select and sum price based different date ranges into those columns. I am looking to make it so only the positive values within the date ranges in the PRICE column can are summed into column CerPay. I think I am close with a case expression, but I can't get it to work out see the code shown below.

Here is what I have that works but it sums all values and puts them in CURPAY:

SELECT 
    Tracking.Name, 
    SUM(IIF(tracking.Date BETWEEN DateSerial(YEAR(DATE()), 1, 1) 
                              AND DateSerial(YEAR(DATE()), 12, 31), Tracking.Price, 0)) AS CurTotal, 
    SUM(IIF(tracking.Date BETWEEN DateSerial(YEAR(DATE()), 1, 1) 
                              AND DateSerial(YEAR(DATE()), MONTH(DATE()) - 1, 31), tracking.price, 0)) AS PreMonth, 
    SUM(IIF(tracking.Date BETWEEN DateSerial(YEAR(DATE()), 1, 1) 
                              AND DateSerial(YEAR(DATE()), MONTH(DATE()) - 1, 31), tracking.price, 0)) AS Curpay
FROM  
    Tracking
WHERE 
    (((Tracking.Date) BETWEEN DateSerial(YEAR(DATE()), 1, 1) 
                          AND DateSerial(YEAR(DATE()), 12, 31)))
GROUP BY 
    Tracking.Name
ORDER BY 
    Tracking.Name;

Here is what I got to with wanting it to sum only the positive values into CURPAY but it keeps failing:

SELECT Tracking.Name, 
   Sum(IIf(tracking.Date Between DateSerial(Year(Date()),1,1) 
         And DateSerial(Year(Date()),12,31),Tracking.Price,0)) AS CurTotal, 
   Sum(IIf(tracking.Date Between DateSerial(Year(Date()),1,1) 
         And DateSerial(Year(Date()),Month(Date())-1,31),tracking.price,0)) AS PreMonth,
   Sum(CASE WHEN IIf(tracking.Date Between DateSerial(Year(Date()),1,1) 
                And DateSerial(Year(Date()),Month(Date())-1,31), tracking.price ,0 )> 0, THEN 
          IIf(tracking.Date Between DateSerial(Year(Date()),1,1) And DateSerial(Year(Date()),Month(Date())-1,31), tracking.price ,0) 
       ELSE 0 
       END)AS Curpay
FROM Tracking
WHERE (((Tracking.Date) Between DateSerial(Year(Date()),1,1) And DateSerial(Year(Date()),12,31)))
GROUP BY Tracking.Name
ORDER BY Tracking.Name;

Solution

  • To sum positive prices, use expression

    IIF(tracking.price>0,tracking.price,0.0)
    

    This is equivalent of expression

    CASE WHEN tracking.price>0 THEN tracking.price ELSE 0.0 END  
    

    Safely calculate end of current month as begin of next month -1 day:

       (DateSerial(Year(Date()),Month(Date())+1,1)-1)
    

    This works also for december. Test (DateSerial(Year(Dateserial(2025,12,31)),Month(Dateserial(2025,12,31))+1,1)-1)=31.12.2025

    end of previous month as first day of current month -1 day

      (DateSerial(Year(Date()),Month(Date()),1)-1)
    

    Instead of DateSerial(Year(Date()),Month(Date())-1,31) - as pointed by @topsail, this is probably incorrect.

    Conditions like

    tracking.Date Between DateSerial(Year(Date()),1,1) 
                 And (DateSerial(Year(Date()),Month(Date()),1)-1)
    

    can be simplified as

    tracking.Date <=(DateSerial(Year(Date()),Month(Date()),1)-1)
    

    because you have condition in WHERE clause

    (([Tracking]![Date] Between DateSerial(Year([Date]),1,1) And DateSerial(Year([Date]),12,31)))
    

    See example

    SELECT Tracking.Name, Sum(Tracking.Price) AS CurTotal
      ,Sum(IIf(tracking.Date Between DateSerial(Year(Date()),1,1) 
                 And (DateSerial(Year(Date()),Month(Date()),1)-1),tracking.price,0)) AS PreMonth
      ,Sum(IIf(tracking.Date Between DateSerial(Year(Date()),1,1) 
                 And (DateSerial(Year(Date()),Month(Date())+1,1)-1),tracking.price,0)) AS CurPay
      ,Sum(IIf(tracking.Date Between DateSerial(Year(Date()),1,1) 
                 And (DateSerial(Year(Date()),Month(Date())+1,1)-1),IIF(tracking.price>0,tracking.price,0),0)) AS CurPayPlus
    FROM Tracking
    WHERE (([Tracking]![Date] Between DateSerial(Year([Date]),1,1) And DateSerial(Year([Date]),12,31)))
    GROUP BY Tracking.Name;