An error occurred while query data from TDengine-client-3.0.2.0-Windows-x64 - tdengine

My SQL: select * from meters order by ts;
Here's the retult from TDengine-server-3.0.2.0-Linux-x64
ts
tv
cs
th
report_time
device_no
2022-12-02 09:22:22.249
30
1
50
2022-12-02 09:22:22.249
d001
2022-12-02 09:59:54.664
27
2
20
2022-12-02 09:59:54.664
d001
2022-12-02 15:55:01.473
29
3
33
2022-12-02 15:55:01.473
d001
2022-12-02 18:25:01.494
15
4
44
2022-12-02 18:25:01.494
d001
2022-12-02 18:25:01.559
15
4
44
2022-12-02 18:25:01.559
d002
2022-12-03 14:36:37.775
15
4
44
2022-12-03 14:36:37.775
d002
but the result from TDengine-client-3.0.2.0-Windows-x64 is different.
ts
tv
cs
th
report_time
device_no
2022-12-01 17:22:22.249
30
1
50
2022-12-01 17:22:22.249
d001
2022-12-01 17:59:54.664
27
2
20
2022-12-01 17:59:54.664
d001
2022-12-01 23:55:01.473
29
3
33
2022-12-01 23:55:01.473
d001
2022-12-02 02:25:01.494
15
4
44
2022-12-02 02:25:01.494
d001
2022-12-02 02:25:01.559
15
4
44
2022-12-02 02:25:01.559
d002
2022-12-02 22:36:37.775
15
4
44
2022-12-02 22:36:37.775
d002
The problem of upgrading to the latest 3.0.2.1 version still exists.
This is init data SQL:
CREATE STABLE meters(
ts timestamp,
tv SMALLINT UNSIGNED,
cs TINYINT UNSIGNED,
th SMALLINT UNSIGNED,
report_time timestamp
) TAGS(
device_no BINARY(60)
);
INSERT INTO d001 USING meters TAGS('d001') VALUES('2022-12-02 09:22:22.249',30,1,50,'2022-12-02 09:22:22.249');
INSERT INTO d001 USING meters TAGS('d001') VALUES('2022-12-02 09:59:54.664',27,2,20,'2022-12-02 09:59:54.664');
INSERT INTO d001 USING meters TAGS('d001') VALUES('2022-12-02 15:55:01.473',29,3,33,'2022-12-02 15:55:01.473');
INSERT INTO d001 USING meters TAGS('d001') VALUES('2022-12-02 18:25:01.494',15,4,44,'2022-12-02 18:25:01.494');
INSERT INTO d002 USING meters TAGS('d002') VALUES('2022-12-02 18:25:01.559',15,4,44,'2022-12-02 18:25:01.559');
INSERT INTO d002 USING meters TAGS('d002') VALUES('2022-12-03 14:36:37.775',15,4,44,'2022-12-03 14:36:37.775');

Related

Need to match ClockIn with Clock out, multiple clocks on same day SQL

I'm trying to get the clock in and clock out times to correspond to each other so that I can calculate hours worked/amount of breaks/time worked within working hours etc. I have a 'Clocking' table that looks like this:
MOCK DATA:
Clock_ID
Employee_ID
Office
Clock_Date
Clock_Time
ActivityID
1
83
Pretoria CBD
29/03/2022
06:43:00
1
2
55
Pretoria CBD
29/03/2022
06:45:00
1
3
54
Pretoria CBD
29/03/2022
07:00:00
1
4
80
Pretoria CBD
29/03/2022
07:00:00
1
5
75
Pretoria CBD
29/03/2022
07:05:00
1
6
54
Pretoria CBD
29/03/2022
10:59:00
2
7
54
Pretoria CBD
29/03/2022
11:50:00
1
8
55
Pretoria CBD
29/03/2022
12:18:00
2
9
55
Pretoria CBD
29/03/2022
12:30:00
1
10
83
Pretoria CBD
29/03/2022
13:03:00
2
11
80
Pretoria CBD
29/03/2022
13:04:00
2
12
83
Pretoria CBD
29/03/2022
13:39:00
1
13
80
Pretoria CBD
29/03/2022
13:39:00
1
14
75
Pretoria CBD
29/03/2022
15:59:00
2
15
54
Pretoria CBD
29/03/2022
16:00:00
2
16
83
Pretoria CBD
29/03/2022
16:00:00
2
17
80
Pretoria CBD
29/03/2022
16:00:00
2
18
55
Pretoria CBD
29/03/2022
16:00:00
2
19
83
Pretoria CBD
30/03/2022
06:46:00
1
20
55
Pretoria CBD
30/03/2022
06:51:00
1
21
80
Pretoria CBD
30/03/2022
06:54:00
1
22
54
Pretoria CBD
30/03/2022
06:54:00
1
23
54
Pretoria CBD
30/03/2022
11:24:00
2
24
54
Pretoria CBD
30/03/2022
12:11:00
1
25
80
Pretoria CBD
30/03/2022
13:03:00
2
26
80
Pretoria CBD
30/03/2022
14:10:00
1
27
54
Pretoria CBD
30/03/2022
16:01:00
2
28
80
Pretoria CBD
30/03/2022
16:01:00
2
29
83
Pretoria CBD
30/03/2022
16:01:00
2
30
55
Pretoria CBD
30/03/2022
16:05:00
2
31
83
Pretoria CBD
31/03/2022
06:48:00
1
32
55
Pretoria CBD
31/03/2022
06:53:00
1
33
54
Pretoria CBD
31/03/2022
06:55:00
1
34
80
Pretoria CBD
31/03/2022
07:09:00
1
35
54
Pretoria CBD
31/03/2022
12:02:00
2
36
54
Pretoria CBD
31/03/2022
12:09:00
1
37
83
Pretoria CBD
31/03/2022
12:34:00
2
38
80
Pretoria CBD
31/03/2022
12:34:00
2
39
83
Pretoria CBD
31/03/2022
13:09:00
1
40
80
Pretoria CBD
31/03/2022
13:09:00
1
41
55
Pretoria CBD
31/03/2022
13:32:00
2
42
54
Pretoria CBD
31/03/2022
15:56:00
2
The ActivityID determines whether it is a 'Clock IN' or 'Clock OUT'
I have used hash tables to separate the data into #clockIN and #clockOUT tables for any given Employee_ID as seen below:
#ClockIN
#ClockOUT
I tried using an inner join on the 'Clock_Date' on the tables to correspond clockINs to clockOUTs, but I get multiple clockOUTS for one clockIN due to the fact that employees can clockIN and OUT multiple times in a day: See below:
As you can see, the records are matched incorrectly, and a just joined on the date.
I cannot think of a way to correctly join them I.e ClockIn at 7:30 must be joined with the EARLIEST clock out on the same day and the next clockIN for that day must be the second earliest ClockIN which must be joined with the second earliest Clock OUT etc.
Would I have to use a cursor? if so, how could I implement that?
I will past all the SQL I used to get to this point.
Drop Table #ClockIn
Drop Table #ClockOut
DROP Table #SortedTimes
DROP Table #WorkBoundries
SELECT Clock_ID, Clock_Date AS Date, Clock_Time
INTO #ClockIn
FROM Clocking
WHERE Employee_ID = 82 AND ActivityID = 1
SELECT * FROM #ClockIn
SELECT Clock_ID, Clock_Date AS Date, Clock_Time
INTO #ClockOut
FROM Clocking
WHERE Employee_ID = 82 AND ActivityID = 2
SELECT * FROM #ClockOut
SELECT #ClockIn.Clock_Time As clockIN, #ClockOut.Clock_Time as ClockOUT, #ClockIn.Date INTO #SortedTimes
FROM #ClockIn
INNER JOIN #ClockOut On #ClockOut.Date = #ClockIN.Date
ORDER BY #ClockIn.Date ASC
SELECT * FROM #SortedTimes
SELECT MIN(clockIn)As TimeIn, MAX(ClockOUT) As TimeOut, [Date] As DayWorked INTO #WorkBoundries
FROM #SortedTimes
GROUP BY [Date]
SELECT * FROM #WorkBoundries
The #WorkBoundries is just to see if the person is clocking IN/OUT within their work hours or not.
Thank you in advance for any assistance
Maybe this can help you
select e.empid,
e.clockdate,
e.clocktime as starttime,
o.clocktime as endtime
from emp e
outer apply (select top 1 e2.clocktime
from emp e2
where e2.empid = e.empid
and e2.activity = 2
and e2.clockdate = e.clockdate
and e2.clocktime > e.clocktime
order by e2.clocktime
) o
where e.activity = 1
order by e.empid, e.clocktime
DBFiddle here
it results in this
empid
clockdate
starttime
endtime
55
2022-03-29
06:45:00.0000000
12:18:00.0000000
55
2022-03-29
12:30:00.0000000
null
83
2022-03-29
06:43:00.0000000
13:03:00.0000000
83
2022-03-29
13:39:00.0000000
16:00:00.0000000
You can do this in a single scan of the base table, and no joins, by using window functions:
WITH NextValues AS (
SELECT *,
NextClockOut = LEAD(CASE WHEN c.ActivityID = 2 THEN c.Clock_Time END)
OVER (PARTITION BY c.Office, c.Employee_ID, c.Clock_Date
ORDER BY c.Clock_Time)
FROM Clocking c
)
SELECT
nv.Employee_ID,
nv.Office,
nv.Clock_Date,
ClockIn = nv.Clock_Time,
ClockOut = nv.NextClockOut
FROM NextValues nv
WHERE nv.ActivityID = 1;
db<>fiddle

Subtract depletion And Limit for SUM

First I'm using AdventureWork2019 as a reference
I have a query where I'm joining 5 Tables
USE [AdventureWorks2019]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Alter PROCEDURE dbo.TestLocation
#UseDate DateTime
AS
BEGIN
SET NOCOUNT ON;
SELECT prodID
,SUM(PurchQty) AS TotalPurchase
,SUM(SalesQty) AS TotalSell
,StartDate
from (
SELECT DISTINCT WO.ProductID AS prodID
, StartDate
,WO.OrderQty AS PurchQty
,SOD.OrderQty AS SalesQty
FROM Sales.SalesOrderDetail SOD
LEFT JOIN Production.WorkOrderRouting WOR ON WOR.ProductID = SOD.ProductID
--LEFT JOIN Production.Location PL ON PL.LocationID = WOR.LocationID
--The above Join is the one for the locationID and it's working Fine
LEFT JOIN Production.WorkOrder WO ON WO.ProductID = SOD.ProductID
FULL OUTER JOIN Purchasing.PurchaseOrderDetail POD ON POD.ProductID = SOD.ProductID
WHERE StartDate = #UseDate
-- AND PL.LocationID >= 10
) Test3
Group by prodID,StartDate
order by prodID ASC, StartDate
END
GO
EXEC TestLocation '2011-07-02 00:00:00.000'
Output(sample):
prodID TotalPurc TotalSell StartDate
717 8 36 2011-07-02 00:00:00.000
730 9 47 2011-07-02 00:00:00.000
744 2 3 2011-07-02 00:00:00.000
747 12 21 2011-07-02 00:00:00.000
749 5 15 2011-07-02 00:00:00.000
761 16 138 2011-07-02 00:00:00.000
775 26 91 2011-07-02 00:00:00.000
777 12 78 2011-07-02 00:00:00.000
802 6 21 2011-07-02 00:00:00.000
804 40 60 2011-07-02 00:00:00.000
806 16 138 2011-07-02 00:00:00.000
807 24 23 2011-07-02 00:00:00.000
810 21 28 2011-07-02 00:00:00.000
811 6 21 2011-07-02 00:00:00.000
813 8 37 2011-07-02 00:00:00.000
817 21 28 2011-07-02 00:00:00.000
And another Table For LocationID (as a warehouse)
SELECT LocationID,CostRate,Availability
FROM Production.Location
WHERE LocationID >= 10
order by CostRate ASC
LocationID CostRate Availability
50 12.25 120.00
60 12.25 120.00
30 14.50 120.00
40 15.75 120.00
45 18.00 80.00
10 22.50 96.00
20 25.00 108.00
What I want to do is to take each LoactionId and ProdID and take TotalPurc to the location and decrement the quantity in the Availability column, each TotalSell will increment the Availability column. The max Availability quantity is 130.
If all locations have no Available quantity that is the Available is 0 for all locations then it will stop.
the above will work with the date specified as you can check the query and run it if you have
AdventureWork2019
simple output to check how I want the data to be:
prodID TotalPurc TotalSell StartDate
717 8 36 2011-07-02 00:00:00.000
730 9 47 2011-07-02 00:00:00.000
744 2 3 2011-07-02 00:00:00.000
747 12 21 2011-07-02 00:00:00.000
749 5 15 2011-07-02 00:00:00.000
LocationID CostRate Availability
50 12.25 120.00
60 12.25 120.00
30 14.50 120.00
40 15.75 120.00
45 18.00 80.00
10 22.50 96.00
20 25.00 108.00
Output :
prodID TotalPurc TotalSell StartDate LocationID Availability Remaining
717 8 36 2011-07-02 00:00:00.000 50 130 18
717 8 36 2011-07-02 00:00:00.000 60 130 8
717 8 36 2011-07-02 00:00:00.000 30 128 0
--what happened above is that I took the (120-8) = 112 then 112+36 = 148 we only can use 130 then the remaining is 18 then we took the next `LocationID` with the least Cost (120+18 = 138 we can use 130 so we took the 8) and used it in the next `LocationID`
730 9 47 2011-07-02 00:00:00.000 30 130 36
730 9 47 2011-07-02 00:00:00.000 40 130 26
730 9 47 2011-07-02 00:00:00.000 45 106 0
744 2 3 2011-07-02 00:00:00.000 45 107 0
747 12 21 2011-07-02 00:00:00.000 45 116 0
749 5 15 2011-07-02 00:00:00.000 45 126 0
--the above is the same as the first 3 rows we subtract and add to the availability
The other condition is that if all locations reached 0 or 130 then stop
How can I do that in SQL Server? I tried using CTE but didn't work well with me and tried the cursor which I think is the best for this kind of thing but didn't achieve anything.
Thank you in advance
Edit :
ALTER FUNCTION GetStockMovment
(
-- Add the parameters for the function here
#ForDate Datetime
)
RETURNS #Sums TABLE (
RemoveQTY Numeric(24, 7),
ADDQTY Numeric(24, 7)
)
AS
BEGIN
Declare #WoSum Numeric(24, 7),
#SODSUM Numeric(24, 7),
#WORSum Numeric(24, 7),
#PODSum Numeric(24, 7)
select #SODSUM = SUM(SOD.OrderQty) from Sales.SalesOrderDetail SOD
INNER JOIN Sales.SalesOrderHeader SOH ON SOD.SalesOrderID = SOH.SalesOrderID
where SOH.OrderDate = #ForDate
select #WoSum = sum(orderQty) from Production.WorkOrder
where StartDate = #ForDate
select #PODSum = sum(POD.OrderQty) from Purchasing.PurchaseOrderDetail POD
INNER JOIN Purchasing.PurchaseOrderHeader POH ON POD.PurchaseOrderID = POH.PurchaseOrderID
where POH.OrderDate = #ForDate
select #WoSum = sum(WO.OrderQty) from Production.WorkOrder WO
where WO.DueDate = #ForDate
INSERT INTO #Sums (RemoveQTY,ADDQTY)
SELECT isnull(#SODSUM,0) + isnull(#WORSum,0) , isnull(#PODSum,0) + isnull(#WoSum,0)
RETURN;
END;
GO
select * from dbo.GetStockMovment ('2014-05-26 00:00:00.000')
Output:
RemoveQTY ADDQTY
189.0000000 5334.0000000
You should use LAG or LEAD function.
https://learn.microsoft.com/en-us/sql/t-sql/functions/lead-transact-sql?view=sql-server-ver15
https://learn.microsoft.com/en-us/sql/t-sql/functions/lag-transact-sql?view=sql-server-ver15

query max date of all customers that falls under a where condition

I would like to query the max date only of all customers that has a value of 25.
Table1
cust_id Date Value
1 2019-10-01 25
1 2019-10-19 35
1 2018-08-27 29
1 2019-07-09 35
1 2019-10-15 55
2 2019-09-26 45
2 2019-10-19 31
2 2019-07-19 8
2 2019-10-02 28
3 2019-09-02 36
3 2019-08-15 39
4 2019-10-15 37
4 2019-10-16 36
4 2018-11-18 27
wrote this query:
select
t1.value,
max(t1.date) as max_date
from table1 t1
where
(t1.date >= '2019-09-30 and t1.date <= 2019-10-31)
and t1.value > 25
group by t1.value
but I am getting:
cust_id Date Value
1 2019-10-01 25
1 2019-10-19 35
1 2019-10-15 55
2 2019-10-19 31
2 2019-10-02 28
4 2019-10-15 37
4 2019-10-16 36
would like to only see the last data entry that is over 25. Something like this:
cust_id Date Value
1 2019-10-19 35
2 2019-10-19 31
4 2018-11-16 36

Average value depending on cumulative value from other column aka running total

I've sifted through the various sql-server tagged threads using AVERAGE and Cumulative as search terms. Various desperate answers, but I can't cobble them together for my needs. The use case is to find the initial average value (cumulative value/cumulative days on) for a time period when cumulative days on is greater than 60 and less than 90.
Below is a table where ID identifies the object, VALUE is the amount reported on a monthly basis and DAYSON is the number of days in that month where the object ran to produce the value. YEARMONTH is date value on which on can sort.
ID VALUE DASYON YEARMONTH
1 166 27 201502
1 1 2 201505
1 569 19 201507
1 312 19 201508
2 364 27 201502
2 328 31 201503
2 242 29 201504
2 273 31 201505
2 174 30 201506
2 188 25 201507
2 203 25 201508
3 474 28 201502
3 521 31 201503
3 465 30 201504
3 473 31 201505
3 434 30 201506
3 404 31 201507
I would like to create a summary table that averages the cumulative value divided by the cumulative days uniquely for each ID where cumulative days is greater than 60 and less than 90. Below is a table that with the cumulative values. (I generated this in Excel)
ID VALUE cumValue DASYON cumDaysOn YEARMONTH
1 166 166 27 27 201502
1 1 167 2 29 201505
1 569 736 19 48 201507
1 312 1048 19 67 201508
2 364 364 27 27 201502
2 328 692 31 58 201503
2 242 934 29 87 201504
2 273 1207 31 118 201505
2 174 1381 30 148 201506
2 188 1569 25 173 201507
2 203 1772 25 198 201508
3 474 474 28 28 201502
3 521 505 31 59 201503
3 465 535 30 89 201504
3 473 566 31 120 201505
3 434 596 30 150 201506
3 404 627 31 181 201507
I try this based on other threads:
SELECT
ID,
Value,
SUM(Value) OVER (ORDER BY ID, YearMonth) [cumValue],
DaysOn,
SUM (DaysOn) OVER (Order by ID, YearMonth) as cumDaysOn,
YearMonth
FROM table
WHERE DAYSON > 0 and Liquid > 0 and YearMonth > 201501
GROUP BY ID, YearMonth, Value, DaysOn
ORDER BY ID, yearmonth
I can't get it to iterate over the ID; it just keeps summing down the column. If I could create a table or view like the one above, then I could always use a select statement and divide cumvalue by cumdayson.
Below is a table to show where I would get the initial average value (InititalAverageValue) based on the criteria:
ID VALUE cumValue DASYON cumDaysOn YEARMONTH InitalAvgValue
1 166 166 27 27 201502
1 1 167 2 29 201505
1 569 736 19 48 201507
1 312 1048 19 67 201508 55
2 364 364 27 27 201502
2 328 692 31 58 201503
2 242 934 29 87 201504 32
2 273 1207 31 118 201505
2 174 1381 30 148 201506
2 188 1569 25 173 201507
2 203 1772 25 198 201508
3 474 474 28 28 201502
3 521 505 31 59 201503
3 465 535 30 89 201504 18
3 473 566 31 120 201505
3 434 596 30 150 201506
3 404 627 31 181 201507
Ultimately what I desire is table as such:
ID InitalAvgValue
1 55
2 32
3 18
Thanks in advance for any help.
The crux is that you need a running total. There are several approaches to calculating running totals, but they have various tradeoffs between simplicity and performance. The "best" approach depends on the expected size of your data set and whether you are using SQL Server 2012 or an earlier version. The following article describes some different options along with the pros and cons:
http://sqlperformance.com/2012/07/t-sql-queries/running-totals
Here's a quick example using correlated subqueries, which may be reasonable for small data sets, but likely would not scale well to larger data:
SELECT
ID,
ROUND(AVG(CAST(CumulativeValue AS FLOAT) / CAST(CumulativeDaysOn AS FLOAT)), 1) AS Average
FROM
(
SELECT
ID,
Value,
DaysOn,
(SELECT SUM(Value) FROM ExampleTable t2 WHERE t1.ID = t2.ID and t2.YearMonth <= t1.YearMonth) AS CumulativeValue,
(SELECT SUM(DaysOn) FROM ExampleTable t2 WHERE t1.ID = t2.ID and t2.YearMonth <= t1.YearMonth) AS CumulativeDaysOn
FROM
ExampleTable t1
) AS ExampleWithTotals
WHERE
CumulativeDaysOn > 60 AND CumulativeDaysOn < 90
GROUP BY
ID
ORDER BY
ID
;
Output:
ID Average
1 15.6
2 10.7
3 16.4

Advanced sql with windowing claus

SELECT a.*,
SUM(s.amount) over(ORDER BY s.month rows unbounded preceding) AS a ,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows unbounded preceding) AS b,
SUM(s.amount) over(PARTITION BY s.month ) AS c_1,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows BETWEEN unbounded preceding AND unbounded following) AS c,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows BETWEEN 1 preceding AND unbounded following) AS d,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows BETWEEN 1 preceding AND 1 following) AS e,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows BETWEEN unbounded preceding AND 1 following) AS f,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows CURRENT ROW) AS g
FROM all_sales s,
(SELECT *
FROM all_sales) a
WHERE s.rowid = a.rowid;
/
--above query give the result shown below what is difference between c_1 and c column.
YEAR MONTH PRD_TYPE_ID EMP_ID AMOUNT A B C_1 C D E F G
1 2006 1 1 21 1.00 1 1 10 10 10 3 3 1
2 2006 1 1 21 2.00 3 3 10 10 10 6 6 2
3 2005 1 2 21 3.00 6 6 10 10 9 9 10 3
4 2005 1 2 22 4.00 10 10 10 10 7 7 10 4
5 2006 2 1 21 5.00 15 5 11 11 11 11 11 5
6 2005 2 1 21 6.00 21 11 11 11 11 11 11 6
7 2005 3 1 21 21 7 7 7 7 7
8 2006 3 2 21 7.00 28 7 7 7 7 7 7 7
9 2005 4 1 21 8.00 36 8 17 17 17 17 17 8
10 2006 4 2 21 9.00 45 17 17 17 17 17 17 9
11 2006 5 2 21 45 10 10 10 10 10
12 2005 5 1 21 10.00 55 10 10 10 10 10 10 10
13 2006 6 1 21 11.00 66 11 23 23 23 23 23 11
14 2005 6 1 21 12.00 78 23 23 23 23 23 23 12
15 2005 7 2 21 13.00 91 13 27 27 27 27 27 13
16 2006 7 1 21 14.00 105 27 27 27 27 27 27 14
17 2005 8 2 21 15.00 120 15 31 31 31 31 31 15
18 2006 8 1 21 16.00 136 31 31 31 31 31 31 16
19 2005 9 2 21 17.00 153 17 35 35 35 35 35 17
20 2006 9 1 21 18.00 171 35 35 35 35 35 35 18
21 2005 10 2 21 19.00 190 19 39 39 39 39 39 19
22 2006 10 1 21 20.00 210 39 39 39 39 39 39 20
23 2006 11 1 21 21.00 231 21 43 43 43 43 43 21
24 2005 11 1 21 22.00 253 43 43 43 43 43 43 22
25 2006 12 2 21 23.00 276 23 47 47 47 47 47 23
26 2005 12 1 21 24.00 300 47 47 47 47 47 47 24
You have the same result because your statements are preaty the same:
SUM(s.amount) over(PARTITION BY s.month ) AS c_1,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows BETWEEN unbounded preceding AND unbounded following) AS c
The cause of it is condition BETWEEN unbounded preceding AND unbounded following because it covers the entire range of partition.
FROM MSDN:
UNBOUNDED PRECEDING - Specifies that the window starts at the first row of the partition. UNBOUNDED PRECEDING can only be specified as window starting point.
UNBOUNDED FOLLOWING - Specifies that the window ends at the last row of the partition. UNBOUNDED FOLLOWING can only be specified as a window end point. For example RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING defines a window that starts with the current row and ends with the last row of the partition.
When together they are equal to PARTITION BY s.month

Resources