Apologies if you are coming here for the first time. This post is a somewhat dense domain specific holding post for some work I did at the weekend to pull together some thoughts.
I was thinking that if I had a list of all sites in the UK I should be able to generate a phasing for each of them based on maybe the area of the site. This would automatically create a general housing land audit for any site that I should put in. I thought I’d try and see if I could write a set of functions that might generate phasing by site. Given that you can get an estimate of the housing boundaries from open street map and that you can get their area it would be possible to get an estimated number of houses per site which could then be used to phase. Going further if you were ever to know planning permission dates you could more accurately use this as a date from which to start phasing.
Ensure you have three tables
T01Sites (PKID, TotalNoHouses, DecisionDate)
T02HousePhasing (PKID, SiteFKID, Year, Completions)
T03 (PKID, TotalNoHouses, DecisionDate, YearofDecision, YearofStart, YearSpread)
T02 is the phasing child table of T01 and T03 is a holding table for a make table that will hold a randomised spread over which you wish to phase the total no of houses. It also randomly predicts when the housing will start on site.
And three queries
Q01 – Make Table Query
SELECT T01Sites.PKID, T01Sites.SiteName, T01Sites.TotalNoHouses, T01Sites.DecisionDate, Year([DecisionDate]) AS YearofDecision, CalculateintYearStartFULLPP([YearofDecision]) AS YearofStart, intYearSpread([TotalNoHouses]) AS YearSpread INTO T03
FROM T01Sites;
Q02 – Select Query
SELECT T03.PKID, T03.SiteName, T03.TotalNoHouses, T03.DecisionDate, T03.YearofStart, T03.YearSpread, Int(T03!TotalNoHouses/T03!YearSpread) AS PerYearSpread, [TotalNoHouses] Mod [YearSpread] AS Remainder
FROM T03
WHERE ((([TotalNoHouses] Mod [YearSpread])=0));
Q03 – Select Query
SELECT T03.PKID, T03.SiteName, T03.TotalNoHouses, T03.DecisionDate, T03.YearofStart, T03.YearSpread, Int(T03!TotalNoHouses/T03!YearSpread) AS PerYearSpread, [TotalNoHouses] Mod [YearSpread] AS Remainder
FROM T03
WHERE ((([TotalNoHouses] Mod [YearSpread])>0));
VBA Function list
The first function randomises the spread in years over which construction might happen on an individual housing site based on the total number of houses on the site.
Public Function intYearSpread(TotalNoHouses As Integer) As Integer
If TotalNoHouses < 2 Then
intYearSpread = 1
ElseIf TotalNoHouses = 2 Then
intYearSpread = Int((TotalNoHouses) * Rnd) + 1
ElseIf TotalNoHouses > 2 And TotalNoHouses < 9 Then
intYearSpread = Int((TotalNoHouses - 2 + 1) * Rnd + 1)
ElseIf TotalNoHouses >= 9 And TotalNoHouses <= 40 Then
intYearSpread = Int((4) * Rnd + 1)
ElseIf TotalNoHouses >= 41 And TotalNoHouses <= 80 Then
intYearSpread = Int((8 - 4 + 1) * Rnd + 4)
ElseIf TotalNoHouses >= 81 And TotalNoHouses <= 200 Then
intYearSpread = Int((8 - 4 + 1) * Rnd + 4)
ElseIf TotalNoHouses >= 201 And TotalNoHouses <= 400 Then
intYearSpread = Int((10 - 6 + 1) * Rnd + 6)
ElseIf TotalNoHouses >= 401 And TotalNoHouses <= 800 Then
intYearSpread = Int((12 - 8 + 1) * Rnd + 8)
Else
intYearSpread = Int((20 - 10 + 1) * Rnd + 10)
End If
'MsgBox intYearSpread
End Function
The first of the next three functions is used in the query to identify a year from which phasing on site will start. I wrote two further functions with the thought that in the future I could create a switch that would allow alternative site starts depending on whether a site has planning permission and depending on the type of planning permission. For example full planning permission would mean starting within three years of the granting of planning permission whereas outline would push it to between 3 and 6 years. A site with an LDP allocation would start further into the future.
Public Function CalculateintYearStartFULLPP(intDecisionDateYear As Integer) As Integer
CalculateintYearStartFULLPP = intDecisionDateYear + (Int((3 - 1 + 1) * Rnd + 1))
End Function
'Not used at present
Public Function CalculateintYearStartPPPP(intDecisionDateYear As Integer) As Integer
CalculateintYearStartPPPP = intDecisionDateYear + (Int((6 - 3 + 1) * Rnd + 3))
End Function
'Not used at present
Public Function CalculateintYearStartLDP(intDecisionDateYear As Integer) As Integer
CalculateintYearStartLDP = intDecisionDateYear + (Int((20 - 8 + 1) * Rnd + 8))
MsgBox CalculateintYearStartLDP
End Function
Function to create phasing IF housing IS perfectly divisible by Year Spread
GRH is an acronym for Generate Randomised Housing
Public Function GRHZero() As Variant
Dim db As DAO.Database
Dim rsSource As DAO.Recordset
Dim rsPhasing As DAO.Recordset
Dim intrsSourcePKID As Integer
Dim intrsSourceYearofStart As Integer
Dim intYearSpread As Integer
Dim intPerYearSpread As Integer
Dim i As Integer
Set db = CurrentDb()
Set rsSource = db.OpenRecordset("Q02")
Set rsPhasing = db.OpenRecordset("T02HousePhasing")
If Not (rsSource.EOF And rsSource.BOF) Then
'There are no records if End of File and Beginning of File are both true
rsSource.MoveFirst
Do Until rsSource.EOF = True
intrsSourcePKID = rsSource!PKID
intrsSourceYearofStart = rsSource!YearofStart
intYearSpread = rsSource!YearSpread
intPerYearSpread = rsSource!PerYearSpread
For i = 1 To intYearSpread
With rsPhasing
rsPhasing.AddNew
rsPhasing!SiteFKID = intrsSourcePKID
rsPhasing!Year = intrsSourceYearofStart
rsPhasing!Completions = intPerYearSpread
rsPhasing.Update
intrsSourceYearofStart = intrsSourceYearofStart + 1
End With
Next i
rsSource.MoveNext
Loop
Else
MsgBox "No Records"
Exit Function
End If
rsPhasing.Close
rsSource.Close
Set rsPhasing = Nothing
Set rsSource = Nothing
Set db = Nothing
End Function
Function to create phasing IF housing IS NOT perfectly divisible by Year Spread and a remainder is put on end
Public Function GRHRemainder() As Variant
Dim db As DAO.Database
Dim rsSource As DAO.Recordset
Dim rsPhasing As DAO.Recordset
Dim intrsSourcePKID As Integer
Dim intrsSourceYearofStart As Integer
Dim intYearSpread As Integer
Dim intPerYearSpread As Integer
Dim intRemainder As Integer
Dim i As Integer
Set db = CurrentDb()
Set rsSource = db.OpenRecordset("Q03")
Set rsPhasing = db.OpenRecordset("T02HousePhasing")
If Not (rsSource.EOF And rsSource.BOF) Then
'There are no records if End of File and Beginning of File are both true
rsSource.MoveFirst
Do Until rsSource.EOF = True
intrsSourcePKID = rsSource!PKID
intrsSourceYearofStart = rsSource!YearofStart
intYearSpread = rsSource!YearSpread
intPerYearSpread = rsSource!PerYearSpread
intRemainder = rsSource!Remainder
For i = 1 To intYearSpread
With rsPhasing
rsPhasing.AddNew
rsPhasing!SiteFKID = intrsSourcePKID
rsPhasing!Year = intrsSourceYearofStart
rsPhasing!Completions = intPerYearSpread
rsPhasing.Update
intrsSourceYearofStart = intrsSourceYearofStart + 1
End With
Next i
With rsPhasing
rsPhasing.AddNew
rsPhasing!SiteFKID = intrsSourcePKID
rsPhasing!Year = intrsSourceYearofStart
rsPhasing!Completions = intRemainder
rsPhasing.Update
intrsSourceYearofStart = intrsSourceYearofStart + 1
End With
rsSource.MoveNext
Loop
Else
MsgBox "No Records"
Exit Function
End If
rsPhasing.Close
rsSource.Close
Set rsPhasing = Nothing
Set rsSource = Nothing
Set db = Nothing
End Function
And the Script to run both the above functions
Public Function GeneratePhasingRecords()
Call GRHZero
Call GRHRemainder
MsgBox "Finished"
End Function