I have a dashboard with python and dash/plotly that receives inputs from the user and then run a query on Google BigQuery.
One of the queries updates a column (PAY_FT), uses other column (PAY_CLEAN) and a string input from the dashboard.
DECLARE cpi STRING DEFAULT "C";
UPDATE `xx.yy.zz` t
SET
PAY_FT = s.PAY_FT
FROM
(
SELECT
RN,
CASE
WHEN RN = 1 AND cpi = "S" AND PAY_SHALE_COR = "PAY" THEN 1
WHEN RN = 1 AND cpi = "C" AND PAY_CLEAN = "PAY" THEN 1
WHEN RN = 1 THEN 0
WHEN RN > 1 AND cpi = "S" AND PAY_SHALE_COR = "PAY" THEN 0.2 + (LAG(PAY_FT, 1) OVER(ORDER BY RN))
WHEN RN > 1 AND cpi = "C" AND PAY_CLEAN = "PAY" THEN 0.2 + (LAG(PAY_FT, 1) OVER(ORDER BY RN))
ELSE (LAG(PAY_FT, 1) OVER(ORDER BY RN))
END
AS PAY_FT
FROM
`xx.yy.zz`
WHERE
DEPTH_M IS NOT NULL
)
s
WHERE
t.RN = s.RN
But it's not working as intended. This query returns the following:
It works until DEPTH_M = 102.2, but after that it dows not return the 0.4 from the previous row. So, for example, if we had a "PAY" in DEPTH_M = 103.2, until 103.0 should return 0.4 and in 103.2 it should be 0.6.
How can I fix it?
Here's a sample of my data: SAMPLE.csv
My desired outpu should be:
DEPTH_M
PAY_CLEAN
PAY_FT
101.2
PAY
0.2
101.4
PAY
0.4
101.6
-
0.4
101.8
-
0.4
102.0
-
0.4
102.2
-
0.4
102.4
-
0.4
102.6
-
0.4
102.8
-
0.4
103.0
-
0.4
103.2
-
0.4
103.4
-
0.4
Let's say that we got another PAY on another row, the output should be:
DEPTH_M
PAY_CLEAN
PAY_FT
101.2
PAY
0.2
101.4
PAY
0.4
101.6
-
0.4
101.8
-
0.4
102.0
-
0.4
102.2
-
0.4
102.4
-
0.4
102.6
-
0.4
102.8
-
0.4
103.0
PAY
0.6
103.2
-
0.6
103.4
-
0.6
Thanks in advance.
on the second thought you can go with this query which is much simpler and does what you want and you don't need to check for RN :
SELECT RN
,0.2 * COUNT(CASE WHEN (cpi = "S" AND PAY_SHALE_COR = "PAY")
OR (cpi = "C" AND PAY_CLEAN = "PAY") THEN 1 END) OVER (ORDER BY RN)
+ SUM(CASE WHEN RN = 1 AND ((cpi = "S" AND PAY_SHALE_COR = "PAY")
OR (cpi = "C" AND PAY_CLEAN = "PAY")) THEN 0.8 ELSE 0 end) OVER () NEW_Pay_FT
FROM `xx.yy.zz`
WHERE DEPTH_M IS NOT NULL
Related
my VBA code runs in mood swings
I created a VBA module to get data from 30 html pages and combine them all into a single table in my worksheet. My approach was to loop through each html page one by one, getting the data and append my worksheet after each loop.
After various adjustments, my code worked quite well, except for one problem that I have spent days but cannot figure out. The thing is the data table that I get is not exactly the same as the table displayed in the website. Sometimes it is correct, sometimes it is not. How come my code or VBA is inherent with “mood swings”, Could someone point out the error for me?
Your help is greatly appreciated.
Cao Doremi
The 1st webpage:
https://www.cophieu68.vn/atbottom.php?currentPage=1&&d=24&type=lo
source table
No. Symbol Lowest
On Current Price +/- Volume Highest
On Book Price EPS P/E
(24_Month)
(24_Month)
1 CVRE2013
0.1 28/07/2021 0.1
0 0 12.1 25/01/2021 0 0 0
2 CTCH2102
0.2 28/07/2021 0.2
0 2,100 4.7 14/05/2021 0 0 0
3 CTCH2003
0.2 27/07/2021 0.2
0 26,100 3.9 22/01/2021 0 0 0
4 CVHM2105
1.2 28/07/2021 1.1
-0.1 50,400 6.4 17/05/2021 0 0 0
5 YEG
15.1 28/07/2021 15.1
0.1 74,200 86.9 10/7/2019 0 -4.1 -3.7
6 CVNM2104
1.2 28/07/2021 0.9
0 46,000 4 25/05/2021 0 0 0
7 CVHM2106
1.1 28/07/2021 1.1
0 45,800 5.8 17/05/2021 0 0 0
Destination table
No. Symbol Lowest
(24_Month) On Current Price +/- Volume Highest
(24_Month) On Book Price EPS P/E
1 CVRE2013 0.1 28/07/2021 0.1 0 0 12.1 25/01/2021 0 0 0
2 CVRE2104 0.2 28/07/2021 0.1 0 44,700 5 14/05/2021 0 0 0
3 CTCH2102 0.2 28/07/2021 0.2 0 135,300 4.7 14/05/2021 0 0 0
4 CTCH2103 0.1 28/07/2021 0.1 0 319,000 3 14/05/2021 0 0 0
5 CVHM2105 1.2 28/07/2021 1.2 0 160,700 6.4 17/05/2021 0 0 0
6 CVHM2106 1.1 28/07/2021 1 0 234,500 5.8 17/05/2021 0 0 0
7 CVNM2104 1.2 28/07/2021 0.9 0 194,000 4 25/05/2021 0 0 0
code:
Sub Gettab()
Dim html As HTMLDocument
Dim table As MSHTML.HTMLTable
Dim sh As Worksheet
Dim td As Object, tr As Object, r As Long, c As Long, i As Integer
Sheets.Add.Name = "webtab" ' => Need to delete the "webtab" worksheet before running the code for the second time
Set sh = ThisWorkbook.Worksheets("webtab")
r = 1
For i = 1 To 30
URL = "http://www.cophieu68.vn/atbottom.php?currentPage=" & str(i) & "&&d=24&type=lo&lang=en"
Set html = New HTMLDocument
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", URL, False
.SetRequestHeader "User-Agent", "Mozilla/5.0"
.send
html.body.innerHTML = .responseText
End With
Set table = html.getElementById("fred")
For Each tr In table.getElementsByTagName("tr") ' Loop through rows topdown
c = 1
For Each td In tr.getElementsByTagName("td") ' Loop through columns in a row (cell by cell, right to left)
sh.Cells(r, c) = td.innerText
c = c + 1
Next
r = r + 1
Next
Set table = Nothing
Set html = Nothing
Set tr = Nothing
Set td = Nothing
Next
End Sub
I'm attempting to rebuild some VBA functions in SQL server 2016 and I'm having difficult making a recursive function work properly.
My attempt below is returning NULL and when I step through the function in debug #returnValue never seems to hold a value even though it appears to recurse correctly.
Can someone please advise how to fix this.
Example expected results:
select [dbo].TickDiff(1.01, 1.05) -- Expect result 4
select [dbo].TickDiff(2.02, 16) -- Expect result 121
Functions:
CREATE FUNCTION [dbo].TickDiff (#odds1 float, #odds2 float)
RETURNS float
AS
BEGIN
DECLARE #returnValue as float
IF (#odds1 > #odds2)
BEGIN
set #returnValue = #returnValue + [dbo].TickDiff([dbo].TicksDown(#odds1), #odds2) + 1
END
ELSE
IF (#odds1 < #odds2)
BEGIN
set #returnValue = #returnValue + [dbo].TickDiff([dbo].TicksUp(#odds1), #odds2) + 1
END
RETURN #returnValue;
END
GO
CREATE FUNCTION [dbo].TicksUp(
#odds float
)
RETURNS float
AS
BEGIN
RETURN
case
when #odds < 1 then 1.02
when #odds >= 1 and #odds <= 1.99 then #odds + 0.01
when #odds >= 2 and #odds <= 2.98 then #odds + 0.02
when #odds >= 3 and #odds <= 3.95 then #odds + 0.05
when #odds >= 4 and #odds <= 5.9 then #odds + 0.1
when #odds >= 6 and #odds <= 9.8 then #odds + 0.2
when #odds >= 10 and #odds <= 19.5 then #odds + 0.5
when #odds >= 20 and #odds <= 29 then #odds + 1.0
when #odds >= 30 and #odds <= 48 then #odds + 2.0
when #odds >= 50 and #odds <= 95 then #odds + 5.0
when #odds >= 100 and #odds < 1000 then #odds + 10
when #odds >= 1000 then 1000
end
END
GO
CREATE FUNCTION [dbo].TicksDown(
#odds float
)
RETURNS float
AS
BEGIN
RETURN
case
when #odds <= 1.01 then 1.01
when #odds >= 1.01 and #odds <= 2 then #odds - 0.01
when #odds >= 2.02 and #odds <= 3 then #odds - 0.02
when #odds >= 3.05 and #odds <= 4 then #odds - 0.05
when #odds >= 4.1 and #odds <= 6 then #odds - 0.1
when #odds >= 6.2 and #odds <= 10 then #odds - 0.2
when #odds >= 10.5 and #odds <= 20 then #odds - 0.5
when #odds >= 21 and #odds <= 30 then #odds - 1.0
when #odds >= 32 and #odds <= 50 then #odds - 2.0
when #odds >= 55 and #odds <= 100 then #odds - 5.0
when #odds >= 110 and #odds < 1000 then #odds - 10
when #odds >= 1000 then 990
end
END
GO
The VBA functions I'm trying to copy are below:
Function TicksDown(ByVal odds As Currency) As Currency
Dim IncrementOdds As Currency
Select Case odds
Case 1.01 To 2
IncrementOdds = 0.01
Case 2.02 To 3
IncrementOdds = 0.02
Case 3.05 To 4
IncrementOdds = 0.05
Case 4.1 To 6
IncrementOdds = 0.1
Case 6.2 To 10
IncrementOdds = 0.2
Case 10.5 To 20
IncrementOdds = 0.5
Case 21 To 30
IncrementOdds = 1
Case 32 To 50
IncrementOdds = 2
Case 55 To 100
IncrementOdds = 5
Case 110 To 1000
IncrementOdds = 10
End Select
If Math.Round(odds - IncrementOdds, 2) >= 1.01 Then
TicksDown = Math.Round(odds - IncrementOdds, 2)
Else
TicksDown = 1.01
End If
End Function
Function TicksUp(ByVal odds As Currency) As Currency
Dim IncrementOdds As Currency
Select Case odds
Case 1 To 1.99
IncrementOdds = 0.01
Case 2 To 2.98
IncrementOdds = 0.02
Case 3 To 3.95
IncrementOdds = 0.05
Case 4 To 5.9
IncrementOdds = 0.1
Case 6 To 9.8
IncrementOdds = 0.2
Case 10 To 19.5
IncrementOdds = 0.5
Case 20 To 29
IncrementOdds = 1
Case 30 To 48
IncrementOdds = 2
Case 50 To 95
IncrementOdds = 5
Case 100 To 1000
IncrementOdds = 10
End Select
If Math.Round(odds + IncrementOdds, 2) <= 1000 Then
TicksUp = Math.Round(odds + IncrementOdds, 2)
Else
TicksUp = 1000
End If
End Function
Function TickDiff(odds1 As Currency, odds2 As Currency) As Long
If odds1 > odds2 Then
odds1 = TicksDown(odds1)
TickDiff = TickDiff(odds1, odds2) + 1
ElseIf odds1 < odds2 Then
odds1 = TicksUp(odds1)
TickDiff = TickDiff(odds1, odds2) + 1
Else
'Found, Exit Recursive Function
End If
End Function
You need to set your #ReturnValue to zero:
DECLARE #returnValue as float = 0.0
That being said, your second example exceeds SQLs max recursion of 32. You may want to rewrite without recursion. Here's an example: http://www.sql-server-helper.com/error-messages/msg-217.aspx
Your #returnValue is not initialized , so it is null. And
set #returnValue = #returnValue + [dbo].TickDiff([dbo].TicksDown(#odds1), #odds2) + 1
evaluates to null.
Try
CREATE FUNCTION [dbo].TickDiff (#odds1 float, #odds2 float)
RETURNS float
AS
BEGIN
DECLARE #returnValue as float = 0.;
IF (#odds1 > #odds2)
BEGIN
set #returnValue = #returnValue + [dbo].TickDiff([dbo].TicksDown(#odds1), #odds2) + 1
END
ELSE
IF (#odds1 < #odds2)
BEGIN
set #returnValue = #returnValue + [dbo].TickDiff([dbo].TicksUp(#odds1), #odds2) + 1
END
RETURN #returnValue;
END
Also case expressions can be simplified because sql-server evaluates when conditions in the order specified.
CREATE FUNCTION [dbo].TicksUp(
#odds float
)
RETURNS float
AS
BEGIN
RETURN
case
when #odds < 1 then 1.02
when #odds <= 1.99 then #odds + 0.01
when #odds <= 2.98 then #odds + 0.02
when #odds <= 3.95 then #odds + 0.05
when #odds <= 5.9 then #odds + 0.1
when #odds <= 9.8 then #odds + 0.2
when #odds <= 19.5 then #odds + 0.5
when #odds <= 29 then #odds + 1.0
when #odds <= 48 then #odds + 2.0
when #odds <= 95 then #odds + 5.0
when #odds < 1000 then #odds + 10
when #odds >= 1000 then 1000
end
END
I am going to try to simplify my objective as well as add all of my vba as my OP was not clear.
I am writing a macro that is to be used to determine a commissions percentage based on a particular strategies (Tier1, Tier2, BPO or Enterprise), a Gross Margin range and contract year. This will need to be looped through about 5,000 rows of data in the final product. I have been trying to nest multiple If-Then statements to achieve my goal however it is not working.
Below is the table for the commissions rates that apply to each of the strategies and then the code that I wrote for this nested If-Then statement.
Looking to try to make this simpler and loop it through the entirety of the rows with data. Goal is to have each cell in column J return a Commission rate determined by the strategy in column i, year in column D and GM in column Z. The strategy has the potential to vary each row down the page.
Would I be better off creating a custom Function?
Kinda crazy task for a first time macro writer. Appreciate all the feedback I have gotten already and look forward to any other ideas to come.
enter image description here
enter image description here
enter image description here
My Code:
Where Column I = Strategy
Where Column D = Year
Where Column Z = Gross Margin
Where Column J = Result of If-Then
where Column C is a defined data set which determines the number of rows in the workbook.
Sub Define_Comm_Rate
Dim LastRow As Long
LastRow = Range("C" & Rows.Count).End(xlUp).Row
If Sheet1.Range("I2") = "BPO" And Sheet1.Range("Z2") >= 0.24 Then
If Sheet1.Range("D2") = 1 Then
Sheet1.Range("J2") = 0.4
Else
If Sheet1.Range("D2") = 2 Then
Sheet1.Range("J2") = 0.3
Else: Sheet1.Range("J2") = 0.15
End If
End If
End If
If Sheet1.Range("I2") = "BPO" And Sheet1.Range("Z2") >= 0.21 And Sheet1.Range("Z2") < 0.24 Then
If Sheet1.Range("D2") = 1 Then
Sheet1.Range("J2") = 0.35
Else
If Sheet1.Range("D2") = 2 Then
Sheet1.Range("J2") = 0.25
Else: Sheet1.Range("J2") = 0.1
End If
End If
End If
If Sheet1.Range("I2") = "BPO" And Sheet1.Range("Z2") >= 0.18 And Sheet1.Range("Z2") < 0.21 Then
If Sheet1.Range("D2") = 1 Then
Sheet1.Range("J2") = 0.3
Else
If Sheet1.Range("D2") = 2 Then
Sheet1.Range("J2") = 0.2
Else: Sheet1.Range("J2") = 0.05
End If
End If
End If
If Sheet1.Range("I2") = "BPO" And Sheet1.Range("Z2") < 0.18 Then
If Sheet1.Range("D2") = 1 Then
Sheet1.Range("J2") = 0.25
Else
If Sheet1.Range("D2") = 2 Then
Sheet1.Range("J2") = 0.15
Else: Sheet1.Range("J2") = 0.05
End If
End If
End If
If Sheet1.Range("I2") = "Enterprise24" Then
If Sheet1.Range("D2") = "1" Then
Sheet1.Range("J2") = 0.4
Else
If Sheet1.Range("D2") = 2 Then
Sheet1.Range("J2") = 0.3
Else: Sheet1.Range("J2") = 0.15
End If
End If
End If
If Sheet1.Range("I2") = "Enterprise21" Then
If Sheet1.Range("D2") = 1 Then
Sheet1.Range("J2") = 0.35
Else
If Sheet1.Range("D2") = 2 Then
Sheet1.Range("J2") = 0.25
Else: Sheet1.Range("J2") = 0.1
End If
End If
End If
If Sheet1.Range("I2") = "Enterprise18" Then
If Sheet1.Range("D2") = 1 Then
Sheet1.Range("J2") = 0.3
Else
If Sheet1.Range("D2") = 2 Then
Sheet1.Range("J2") = 0.2
Else: Sheet1.Range("J2") = 0.05
End If
End If
End If
If Sheet1.Range("I2") = "Enterprise00" Then
If Sheet1.Range("D2") = 1 Then
Sheet1.Range("J2") = 0.25
Else
If Sheet1.Range("D2") = 2 Then
Sheet1.Range("J2") = 0.15
Else: Sheet1.Range("J2") = 0.05
End If
End If
End If
If Sheet1.Range("I2") = "Tier1" Then
If Sheet1.Range("Z2") > 0.4 Then
Sheet1.Range("J2") = 0.5
Else
If Sheet1.Range("Z2") <= 0.4 And Sheet1.Range("Z2") > 0.25 Then
Sheet1.Range("J2") = (1 * Sheet1.Range("Z2")) + 0.1
Else
If Sheet1.Range("Z2") <= 0.25 And Sheet1.Range("Z2") > 0.075 Then
Sheet1.Range("J2") = (2 * Sheet1.Range("Z2")) - 0.15
Else
If Sheet1.Range("Z2") <= 0.075 And Sheet1.Range("Z2") > 0 Then
Sheet1.Range("J2") = 0
Else: Sheet1.Range("J2") = 0.5
End If
End If
End If
End If
End If
If Sheet1.Range("I2") = "Tier1-100" Then
If Sheet1.Range("Z2") > 0.4 Then
Sheet1.Range("J2") = 0.5
Else
If Sheet1.Range("Z2") <= 0.4 And Sheet1.Range("Z2") > 0.25 Then
Sheet1.Range("J2") = (1 * Sheet1.Range("Z2")) + 0.1
Else
If Sheet1.Range("Z2") <= 0.25 And Sheet1.Range("Z2") > 0.075 Then
Sheet1.Range("J2") = (2 * Sheet1.Range("Z2")) - 0.15
Else
If Sheet1.Range("Z2") <= 0.075 And Sheet1.Range("Z2") > 0 Then
Sheet1.Range("J2") = 0
Else: Sheet1.Range("J2") = 0.5
End If
End If
End If
End If
End If
If Sheet1.Range("I2") = "Tier2" Then
If Sheet1.Range("Z2") > 0.35 Then
Sheet1.Range("J2") = 0.5
Else
If Sheet1.Range("Z2") <= 0.35 And Sheet1.Range("Z2") > 0.25 Then
Sheet1.Range("J2") = (1 * Sheet1.Range("Z2")) + 0.15
Else
If Sheet1.Range("Z2") <= 0.25 And Sheet1.Range("Z2") > 0.05 Then
Sheet1.Range("J2") = (2 * Sheet1.Range("Z2")) - 0.1
Else
If Sheet1.Range("Z2") <= 0.05 And Sheet1.Range("Z2") > 0 Then
Sheet1.Range("J2") = 0
Else: Sheet1.Range("J2") = 0.5
End If
End If
End If
End If
End If
If Sheet1.Range("I2") = "Tier2-100" Then
If Sheet1.Range("Z2") > 0.35 Then
Sheet1.Range("J2") = 0.5
Else
If Sheet1.Range("Z2") <= 0.35 And Sheet1.Range("Z2") > 0.25 Then
Sheet1.Range("J2") = (1 * Sheet1.Range("Z2")) + 0.15
Else
If Sheet1.Range("Z2") <= 0.25 And Sheet1.Range("Z2") > 0.05 Then
Sheet1.Range("J2") = (2 * Sheet1.Range("Z2")) - 0.1
Else
If Sheet1.Range("Z2") <= 0.05 And Sheet1.Range("Z2") > 0 Then
Sheet1.Range("J2") = 0
Else: Sheet1.Range("J2") = 0.5
End If
End If
End If
End If
End If
Sheet1.Range("J2").AutoFill Destination:=Sheet1.Range("J2:J" & LastRow)
Application.Calculate
End Sub
I'm going to offer a non-VBA approach to this using INDIRECT, INDEX, MATCH, and a few tables. My thought is that instead of coding lots of nested IF's, with hard-coded values, in VBA, you should be able to do this with lookup tables. (Disclaimer: this was also a fun intellectual exercise.)
First, create a table similar to the Commissions Table you already have and name it your specific strategy, e.g. "BPO", under Formulas > Name Manager. I created mine on a separate sheet named "Tables". Note that I used 1 in row 1 as your max (and unrealistic) gross margin. I also added 1, 2, and 3 in cells B1, C1, and D1 respectively. You'd need to create similar tables for your other strategies, and put them under the BPO table.
Then in column J on your data tab, enter this formula: =INDEX(INDIRECT(I2),MATCH(Z2,INDIRECT(I2&"["&Z$1&"]"),-1),MATCH(D2,Tables!$A$1:$D$1,1))
This INDEX formula has 3 main parts:
INDIRECT(I2) - this returns the array comprising the table you have named "BPO" - so you know you're looking at the table appropriate to that particular strategy.
MATCH(Z2,INDIRECT(I2&"["&Z$1&"]"),-1) - this looks up your gross margin in column Z against the table (BPO), looking in the column[Gross Margin]. The last argument of MATCH (match type) is -1, meaning that it finds the smallest value that is greater than or equal to your gross margin (note that in the table, Gross Margin is sorted in descending order). So for example, if your Gross Margin is 0.22, the MATCH will return 0.2399.
MATCH(D2,Tables!$A$1:$D$1,1) - This looks up the year, and tries to find the largest value that is less than or equal to it. So if the year is 1, 2, or 3, the MATCH will return 1, 2, or 3, respectively, but if the year is greater than 3, the MATCH returns 3.
Columns AB and AC in the second screenshot are just the results of 2. and 3. above, included to show that the correct commission value is being returned. Note that the "Year Column" is not Year 2 or Year 3, but the 2nd or 3rd column in the BPO table, i.e. Year 1 or Year 2 respectively.
Thanks for all the input/feedback.
Due to added complexity of additional sales plans needing to be incorporated as well as needing the flexibility to add/remove sales plans at any time, I ended up writing a custom Function.
Function Commissions(Strategy As String, GM As Variant, YR As Variant) As Variant
If Strategy = "BPO" And GM >= 0.24 And YR = 1 Then
Commissions = 0.4
ElseIf Strategy = "BPO" And GM >= 0.24 And YR = 2 Then
Commissions = 0.3
ElseIf Strategy = "BPO" And GM >= 0.24 And YR >= 3 Then
Commissions = 0.15
ElseIf Strategy = "BPO" And GM >= 0.21 And GM < 0.24 And YR = 1 Then
Commissions = 0.35
ElseIf Strategy = "BPO" And GM >= 0.21 And GM < 0.24 And YR = 2 Then
Commissions = 0.25
ElseIf Strategy = "BPO" And GM >= 0.21 And GM < 0.24 And YR >= 3 Then
Commissions = 0.1
ElseIf Strategy = "BPO" And GM >= 0.18 And GM < 0.21 And YR = 1 Then
Commissions = 0.3
ElseIf Strategy = "BPO" And GM >= 0.18 And GM < 0.21 And YR = 2 Then
Commissions = 0.2
ElseIf Strategy = "BPO" And GM >= 0.18 And GM < 0.21 And YR >= 3 Then
Commissions = 0.05
ElseIf Strategy = "BPO" And GM < 0.18 And YR = 1 Then
Commissions = 0.25
ElseIf Strategy = "BPO" And GM < 0.18 And YR = 2 Then
Commissions = 0.15
ElseIf Strategy = "BPO" And GM < 0.18 And YR >= 3 Then
Commissions = 0.05
''all other strategies continued below....''
End If
End Function
I have a ASP function as below for rounding up the amount:
function GetRoundedVal(amount)
NoOfRight = right(formatnumber(amount,2),1)
if NoOfRight = 0 then
roundedAmount = amount
elseif NoOfRight = 1 then
roundedAmount = amount - 0.01
elseif NoOfRight = 2 then
roundedAmount = amount - 0.02
elseif NoOfRight = 3 then
roundedAmount = amount + 0.02
elseif NoOfRight = 4 then
roundedAmount = amount + 0.01
elseif NoOfRight = 5 then
roundedAmount = amount
elseif NoOfRight = 6 then
roundedAmount = amount - 0.01
elseif NoOfRight = 7 then
roundedAmount = amount - 0.02
elseif NoOfRight = 8 then
roundedAmount = amount + 0.02
elseif NoOfRight = 9 then
roundedAmount = amount + 0.01
else
end if
GetRoundedVal = roundedAmount
end function
The result should be like this:
+----------------+--------+
| Original Value | Result |
+----------------+--------+
| 19.91 | 19.90 | Original Value - 0.01
| 19.92 | 19.90 | Original Value - 0.02
| 19.93 | 19.95 | Original Value + 0.02
| 19.94 | 19.95 | Original Value + 0.01
| 19.95 | 19.95 |
| 19.96 | 19.95 | Original Value - 0.01
| 19.97 | 19.95 | Original Value - 0.02
| 19.98 | 20.00 | Original Value + 0.02
| 19.99 | 20.00 | Original Value + 0.01
+----------------+--------+
The question is can we do this directly on T-SQL?
SQL Server V14.
If it even possible.
Thanks.
You can try this.
DECLARE #MyTable TABLE(OriginalValue DECIMAL(18,2))
INSERT INTO #MyTable VALUES (19.91), (19.92), (19.93), (19.94), (19.95), (19.96), (19.97), (19.98), (19.99)
SELECT
OriginalValue,
ROUND( ( OriginalValue / 0.05 ), 0, 0 ) * 0.05 Result
FROM #MyTable
Result:
OriginalValue Result
--------------------------------------- ---------------------------------------
19.91 19.90000000
19.92 19.90000000
19.93 19.95000000
19.94 19.95000000
19.95 19.95000000
19.96 19.95000000
19.97 19.95000000
19.98 20.00000000
19.99 20.00000000
try This
DECLARE #Inp TABLE
(
Org DECIMAL(10,4),
Res DECIMAL(10,2)
)
INSERT INTO #Inp
(
Org
)
VALUES(19.91),
(19.92),
(19.93),
(19.94),
(19.95),
(19.96),
(19.97),
(19.98),
(19.99)
SELECT
*,
Result = CAST(
Org +
CASE RIGHT(CAST(Org AS DECIMAL(10,2)),1)
WHEN 1 THEN -0.01
WHEN 2 THEN -0.02
WHEN 3 THEN 0.02
WHEN 4 THEN 0.01
WHEN 5 THEN 0
WHEN 6 THEN -0.01
WHEN 7 THEN -0.02
WHEN 8 THEN 0.02
WHEN 9 THEN 0.01
ELSE 0 END
AS DECIMAL(10,2))
FROM #Inp
----------
I wrote this code to try and assign a value to a variable based on the value of another variable generated using vba's Rnd() function and if statements but for some reason its giving me the "end if without block if error." This is just a portion of the code, I iterate this process 5 times for the 5 different products and do 10000 iterations of the number generators aggregating the results. Initially I tried it this way nesting everything, but when that didnt work I tried doing single if statements and same deal. Any help with this would be awesome.
For i = 0 To 10000
ProdE = Rnd()
ProdF = Rnd()
ProdG = Rnd()
ProdH = Rnd()
ProdI = Rnd()
If ProdE <= 0.1 Then DaysLateE = 2
If 0.1 < ProdE <= 0.2 Then DaysLateE = 3
If 0.2 < ProdE <= 0.3 Then DaysLateE = 4
If 0.3 < ProdE <= 0.4 Then DaysLateE = 5
If 0.4 < ProdE <= 0.5 Then DaysLateE = 6
If 0.5 < ProdE <= 0.6 Then DaysLateE = 7
If 0.6 < ProdE <= 0.7 Then DaysLateE = 8
If 0.7 < ProdE <= 0.8 Then DaysLateE = 9
If 0.8 < ProdE <= 0.9 Then DaysLateE = 10
If 0.9 < ProdE <= 1 Then DaysLateE = 11
End If
End If
End If
End If
End If
End If
End If
End If
End If
End If
TotalDaysLateE = DaysLateE + 8
SumDaysLateE = SumDaysLateE + TotalDaysLateE
If TotalDaysLateE > 15 Then CountE = CountE + 1
End If
The syntax for If allows two variants:
"Inline"
If {bool-expression} Then {do something}
"Block"
If {bool-expression} Then
{do something}
End If
An End If token is illegal when you're using the "inline" syntax.
So this (i.e. removing the End If tokens) makes your code compilable again:
If ProdE <= 0.1 Then DaysLateE = 2
If 0.1 < ProdE <= 0.2 Then DaysLateE = 3
If 0.2 < ProdE <= 0.3 Then DaysLateE = 4
If 0.3 < ProdE <= 0.4 Then DaysLateE = 5
If 0.4 < ProdE <= 0.5 Then DaysLateE = 6
If 0.5 < ProdE <= 0.6 Then DaysLateE = 7
If 0.6 < ProdE <= 0.7 Then DaysLateE = 8
If 0.7 < ProdE <= 0.8 Then DaysLateE = 9
If 0.8 < ProdE <= 0.9 Then DaysLateE = 10
If 0.9 < ProdE <= 1 Then DaysLateE = 11
However, as #Rohan K suggested, a better option would be to use a Select Case construct, because right now, all these conditions are evaluated all the time - with a Select Case block, execution would exit the Select block after finding a matching condition, and as a bonus you gain readabiilty:
Select Case ProdE
Case Is <= 0.1
DaysLateE = 2
Case Is <= 0.2
DaysLateE = 3
Case Is <= 0.3
DaysLateE = 4
Case Is <= 0.4
DaysLateE = 5
Case Is <= 0.5
DaysLateE = 6
Case Is <= 0.6
DaysLateE = 7
Case Is <= 0.7
DaysLateE = 8
Case Is <= 0.8
DaysLateE = 9
Case Is <= 0.9
DaysLateE = 10
Case Is <= 1
DaysLateE = 11
Case Else
'DaysLateE = ??
End Select
So, what happens when ProdE is greater than or equal to 1? (hadn't read where ProdE came from, nevermind) It seems there's a straight linear relationship between the value of ProdE and DaysLateE - you could try to come up with a formula to calculate it instead.
This probably isn't perfect, but comes pretty close:
DaysLateE = Int(ProdE * 10 - 0.000000000001) + 2
And then you don't need If or Select blocks.
The problem is your final If statement there. It is completely valid syntax to have an If statement all on one line without an End If. So when you put that End If there it is expecting an If statement with lines after it.
These two would be valid without an error
If TotalDaysLate > 15 then CountE = CountE + 1
Or
If TotalDaysLate > 15 Then
CountE = CountE + 1
End If
Try this: I would suggest Use Select Case incases like this
For i = 0 To 10000
ProdE = Rnd()
ProdF = Rnd()
ProdG = Rnd()
ProdH = Rnd()
ProdI = Rnd()
If ProdE <= 0.1 Then
DaysLateE = 2
End If
If 0.1 < ProdE And ProdE <= 0.2 Then
DaysLateE = 3
End If
If 0.2 < ProdE And ProdE <= 0.3 Then
DaysLateE = 4
End If
If 0.3 < ProdE And ProdE <= 0.4 Then
DaysLateE = 5
End If
If 0.4 < ProdE And ProdE <= 0.5 Then
DaysLateE = 6
End If
If 0.5 < ProdE And ProdE <= 0.6 Then
DaysLateE = 7
End If
If 0.6 < ProdE And ProdE <= 0.7 Then
DaysLateE = 8
End If
If 0.7 < ProdE And ProdE <= 0.8 Then
DaysLateE = 9
End If
If 0.8 < ProdE And ProdE <= 0.9 Then
DaysLateE = 10
End If
If 0.9 < ProdE And ProdE <= 1 Then
DaysLateE = 11
End If
TotalDaysLateE = DaysLateE + 8
SumDaysLateE = SumDaysLateE + TotalDaysLateE
If TotalDaysLateE > 15 Then
CountE = CountE + 1
End If
When you use single line ifs you don't need to write the End if. Check this: https://msdn.microsoft.com/en-us/library/office/gg251599.aspx
Thinking about your branching and conditional path, and for 10000 iterations, I'd suggest to just Bifurcate your If... Then statement. Better yet, use this in conjunction with two smaller Case... Select for an easily readable combination of all the suggestions. FASTER!
If ProdE <= 0.5 Then
If ProdE <= 0.1 Then DaysLateE = 2
If 0.1 < ProdE <= 0.2 Then DaysLateE = 3
If 0.2 < ProdE <= 0.3 Then DaysLateE = 4
If 0.3 < ProdE <= 0.4 Then DaysLateE = 5
If 0.4 < ProdE <= 0.5 Then DaysLateE = 6
Else
If 0.5 < ProdE <= 0.6 Then DaysLateE = 7
If 0.6 < ProdE <= 0.7 Then DaysLateE = 8
If 0.7 < ProdE <= 0.8 Then DaysLateE = 9
If 0.8 < ProdE <= 0.9 Then DaysLateE = 10
If 0.9 < ProdE <= 1 Then DaysLateE = 11
End If