Decimal to HH:MM Conversion - sql-server

I have a table and I want to update the Duration column which of datatype Decimal to HH:MM format.
ECode Duration
101 101.75
101 69.56
102 54.60
103 54.97
The output should be like this:
ECode Duration
101 102.15
101 69.56
102 55
103 55.37
We are calculating the time after the decimal and if after decimal 60 or more then 60 will be there we are adding 1 before decimal and remaining after subtraction from 60 we are showing as it is.
Example 101.75, here after decimal 75 is there so firstly we check it is greater than or equal to 60. If yes then subtract 60 and add 1 before decimal and put the remaining 15 after decimal. So the result should be 102.15.
Please share query if possible to solve this issue.

This should do it:
update thistable
set duration = duration + 0.4
where duration - floor(duration) >= 0.6

update YourTable set
Duration = floor(Duration) +
cast(((Duration - floor(Duration))*100) as int) / 60 +
cast((cast((Duration - floor(Duration)) * 100 as int) % 60) as float) / 100

I guess you would do something like ("pseudo" code of some sort):
String reorder(String x) {
String parts[] = x.split(.);
if(parts.length < 2) x;
// eval as integers:
if(parts[1] < 60) return x;
if(parts[1] > 60) return (parts[0]+(parts[1]/60))+"."+(parts[1]%60);
return parts[0]+1;
}
But exactly how you do it depends whether you're doing in a script, some application and the language you're using...

Related

Writing formulation in SAS

I have the following SAS dataset:
A B C1 C2 C2
Part1 100 50 20 2 0.1
Part2 100 10 30 5 0.5
Part3 100 80 15 9 0.7
Part4 100 60 58 3 0.9
I have, for each Part, a cost function defined as such:
F1(Part1) = C1,part1 + C2,part1*P1 + C3,part1*P1^2
F2(Part2) = C1,part2 + C2,part2*P2 + C3,part2*P2^2
F3(Part3) = C1,part3 + C2,part3*P3 + C3,part3*P3^2
F4(Part4) = C1,part4 + C2,part4*P4 + C3,part4*P4^2
I defined/declared the following parameters:
set <str> Parts; *set for all parts
num nseg{Parts}; *number of segments for each part cost function
num coef{nseg,Parts} *the C values from the dataset
I'm trying to write a formulation to represent the sum of the cost functions
F1(Part1)+ ... +FN(PartN), and came up with this:
TotalCost = sum{p in Parts, j in 1..nseg[p]} (Coef[n,p] + Coef[n,p]*P[p] + Coef[n,p]*P[p]^2).
Unfortunately I'm not getting it quite right. Any suggestions on best way to do this?
Thank you very much!

Rounding Down number to the 60

How can I round a number to interval of 60 ?
For instance if I have number 61, It should round of to 60 and if number is 150, it should round of to 120 and in case of 59 it should round off to zero.
To truncate values multiply by 60 and divide by 60. See demo:
SELECT 61/60*60 --result: 60
SELECT 59/60*60 --result: 0
Number must be int (bigint, smallint, tinyint). If it's not, use CAST/CONVERT.
See also Division (Transact SQL):
If an integer dividend is divided by an integer divisor, the result is
an integer that has any fractional part of the result truncated.
ugly but it works:
Integer Division Then Multiply
SELECT (125 / 60 ) * 60
Think this is what you're after
DECLARE #TestVal INT = 59
SELECT #TestVal - (#TestVal % 60)
SET #TestVal = 61
SELECT #TestVal - (#TestVal % 60)
SET #TestVal = 150
SELECT #TestVal - (#TestVal % 60)
Alternative is to use the modulus operator to get the remainder of a division by 60 then subtract it:
% (Modulus) (Transact-SQL)
Returns the remainder of one number divided by another.
For example:
declare #valueToTest int = 150
select #valueToTest - (#valueToTest % 60) as result
-- result: 120
So this gets the remainder when you divide the #valueToTest by 60 and subtracts it from the original #valueToTest.
I'd prefer FLOOR over relying on Integer division, it's what FLOOR is for. example
DECLARE #YourVal DECIMAL(10,4) = 220.1234;
SELECT #YourVal / 60 * 60, FLOOR(#YourVal / 60) * 60;

Bound my result to [-1,1] in SAS

I am calculating a fraction based on the payments made in four years and I wish to put a cap on my fraction such that it can only be between -1 and 1. Subsequently I'd like to make the following fractions 0 if the cap is maxxed out - an example would be:
data want;
input payment1 payment2 payment3 payment4 fraction1 fraction2 fraction3;
datalines;
100 25 25 25 0.25 0.25 0.25
150 50 50 50 0.33 0.33 0.33
50 10 10 10 0.2 0.2 0.2
10 50 60 70 1 0 0
;
run;
I've been looking at the ceiling function with the following code
data want2;
set want;
array fraction(3) fraction1 - fraction3;
array payment(4) payment1 - payment4;
do i = 2 to 4;
fraction(i-1) = payment(i)/payment(1);
end;
run;
data want3;
set want2;
array fraction(3) fraction1 - fraction3;
array fract(3) fract1-fract3;
do i = 1 to 3;
fract = ceil (fraction,1);
end;
drop i;
run;
but I am getting this error
ERROR 72-185: The CEIL function call has too many arguments.
So in all i'm looking for a way to calculate the fraction of the payments and then make a ceiling at one, then once the ceiling is hit, the subsequent fractions must be zero (which could be done I suppose by just doing an IF-THEN)
The ceil function is a type of rounding. You need min and max:
do i = 1 to 3;
fract = min(max(fraction, -1) ,1);
end;

Working with an upper-triangular array in SAS (challenge +2 Points)

I'm looking to improve my code efficiency by turning my code into arrays and loops. The data i'm working with starts off like this:
ID Mapping Asset Fixed Performing Payment 2017 Payment2018 Payment2019 Payment2020
1 Loan1 1 1 1 90 30 30 30
2 Loan1 1 1 0 80 20 40 20
3 Loan1 1 0 1 60 40 10 10
4 Loan1 1 0 0 120 60 30 30
5 Loan2 ... ... ... ... ... ... ...
So For each ID (essentially the data sorted by Mapping, Asset, Fixed and then Performing) I'm looking to build a profile for the Payment Scheme.
The Payment Vector for the first ID looks like this:
PaymentVector1 PaymentVector2 PaymentVector3 PaymentVector4
1 0.33 0.33 0.33
It is represented by the formula
PaymentVector(I)=Payment(I)/Payment(1)
The above is fine to create in an array, example code can be given if you wish.
Next, under the assumption that every payment made is replaced i.e. when 30 is paid in 2018, it must be replaced, and so on.
I'm looking to make a profile that shows the outflows (and for illustration, but not required in code, in brackets inflows) for the movement of the payments as such - For ID=1:
Payment2017 Payment2018 Payment2019 Payment2020
17 (+90) -30 -30 -30
18 N/A (+30) -10 -10
19 N/A N/A (+40) -13.3
20 N/A N/A N/A (+53.3)
so if you're looking forwards, the rows can be thought of what year it is and the columns representing what years are coming up.
Hence, in year 2019, looking at what is to be paid in 2017 and 2018 is N/A because those payments are in the past / cannot be paid now.
As for in year 2018, looking at what has to be paid in 2019, you have to pay one-third of the money you have now, so -10.
I've been working to turn this dataset row by row into the array but there surely has to be a quicker way using an array:
The Code I've used so far looks like:
Data Want;
Set Have;
Array Vintage(2017:2020) Vintage2017-Vintage2020;
Array PaymentSchedule(2017:2020) PaymentSchedule2017-PaymentSchedule2020;
Array PaymentVector(2017:2020) PaymentVector2017-PaymentVector2020;
Array PaymentVolume(2017:2020) PaymentVolume2017-PaymentVolume2020;
do i=1 to 4;
PaymentVector(i)=PaymentSchedule(i)/PaymentSchedule(1);
end;
I'll add code tomorrow... but the code doesn't work regardless.
data have;
input
ID Mapping $ Asset Fixed Performing Payment2017 Payment2018 Payment2019 Payment2020; datalines;
1 Loan1 1 1 1 90 30 30 30
2 Loan1 1 1 0 80 20 40 20
3 Loan1 1 0 1 60 40 10 10
4 Loan1 1 0 0 120 60 30 30
data want(keep=id payment: fraction:);
set have;
array p payment:;
array fraction(4); * track constant fraction determined at start of profile;
array out(4); * track outlay for ith iteration;
* compute constant (over iterations) fraction for row;
do i = dim(p) to 1 by -1;
fraction(i) = p(i) / p(1);
end;
* reset to missing to allow for sum statement, which is <variable> + <expression>;
call missing(of out(*));
out(1) = p(1);
do iter = 1 to 4;
p(iter) = out(iter);
do i = iter+1 to dim(p);
p(i) = -fraction(i) * p(iter);
out(i) + (-p(i)); * <--- compute next iteration outlay with ye olde sum statement ;
end;
output;
p(iter) = .;
end;
format fract: best4. payment: 7.2;
run;
You've indexed your arrays with 2017:2020 but then try and use them using the 1 to 4 index. That won't work, you need to be consistent.
Array PaymentSchedule(2017:2020) PaymentSchedule2017-PaymentSchedule2020;
Array PaymentVector(2017:2020) PaymentVector2017-PaymentVector2020;
do i=2017 to 2020;
PaymentVector(i)=PaymentSchedule(i)/PaymentSchedule(2017);
end;

Round 916.984800 to 916.99

Is it possible to round 916.984800 to 916.99 in SQL Server?
I've tried as below but I don't want '+ 0.1' as my solution.
Round((((424.53 - 0) * 36) * (6 / 100)),2) + .01 as [Amount]
or
Round((((424.53 - 0) * 36) * (0.06)),2) + .01 as [Amount]
Thanks
This produces expected output:
SELECT CEILING((424.53 - 0) * 36 * 0.06 * 100) / 100 AS [Amount]
Amount
----------
916.990000
What happens?
SELECT (424.53 - 0) * 36 * 0.06 * 100
This returns 91698.4800, CEILING returns the smallest integer greater than, or equal to, the specified numeric expression, in your case 91699, and later I just divide it by 100, which brings expected result.

Resources