Rounding the value to the nearest 50 - sql-server

I am trying to round down the value to the nearest 50.
1-50 it should round down to below 00 and when its 51-rest then it should round down to 50
ex:
245 (until 1-49) its should round down to 200
258 (from 50-99)then it should round down to 250
I tried this,its wrking good but I need smething other than case statement
#ResultAmount = ROUND(#ResultAmount, -2, 1) +
CASE WHEN RIGHT(CONVERT(INT, FLOOR(#ResultAmount)), 2) IN (00, 50)
THEN RIGHT(CONVERT(INT, FLOOR(#ResultAmount)), 2)
WHEN RIGHT(CONVERT(INT, FLOOR(#ResultAmount)), 2) BETWEEN 1 AND 49
THEN 00
WHEN RIGHT(CONVERT(INT, FLOOR(#ResultAmount)), 2) BETWEEN 51 AND 99
THEN 50
END
Thanks in advance!!!

This is all you need
SELECT FLOOR(#ResultAmount / 50) * 50;
e.g below
declare #ResultAmount decimal(10,2) = 249;
SELECT FLOOR(#ResultAmount / 50) * 50;
SET #ResultAmount = 250;
SELECT FLOOR(#ResultAmount / 50) * 50;
SET #ResultAmount = 200;
SELECT FLOOR(#ResultAmount / 50) * 50;
SET #ResultAmount = 199;
SELECT FLOOR(#ResultAmount / 50) * 50;

It sounds like numbers 0-50 get rounded up to "50", but any number larger than that should just get rounded to the nearest 50. Something like the following should work:
(CASE WHEN f1/50 < 1 THEN 1 ELSE ceiling(f1/50) END) * 50 AS rounded_to_50

You can simply divide the number by 50, round then multiply by 50 again, eg:
select cast(round(#i/50.0,0)*50 as int)
This will return 500 if #i is 524 but 550 if #i is 525.
You can create a function to make this easier:
create function fn_Round_By(#input int,#divider float)
returns int
as
begin
RETURN (cast(round(#input/#divider,0)*#divider as int));
end
Again, select dbo.fn_Round_By(525,50) returns 550 andselect dbo.fn_Round_By(524,50)` returns 500.
If you want values less than 50 to round up to 50, you can use a simple CASE, eg:
create function fn_Round_By(#input int,#divider float)
returns int
as
begin
RETURN (
CASE
WHEN #input <=#divider then #divider
else cast(round(#input/#divider,0)*#divider as int)
END
);
end
Rounding down is performed by the FLOOR function so a function that rounded down to a specific interval would be:
create function fn_Floor_By(#input int,#divider float)
returns int
as
begin
RETURN (cast(FLOOR(#input/#divider)*#divider as int));
end
or, preserving the logic that rounds up anything under 50:
create function fn_Floor_By(#input int,#divider float)
returns int
as
begin
RETURN (
CASE
WHEN #input <=#divider then #divider
else cast(FLOOR(#input/#divider)*#divider as int)
END
);
end

You can calculate modulo 50 and use this to reduce the original value
DECLARE #ResultAmount int = 243
SELECT #ResultAmount - (#ResultAmount%50)

Related

Issue while adding values in SQL Server

Please read again till end (description updated)
I want something like this.
ex :
if (7200 / 42) is float then
floor(7200/42) + [7200 - {(floor(7200/42)) * 42}] / 10 ^ length of [7200 - {(floor(7200/42)) * 42}]
STEP : 1 => 171 + ((7200 - (171*42))/10 ^ len(7200-7182))
STEP : 2 => 171 + ((7200 - 7182)/10 ^ len(18))
STEP : 3 => 171 + (18/10 ^ 2)
STEP : 4 => 171 + (18/100)
STEP : 5 => 171 + 0.18
STEP : 6 => 171.18
I have written the code in SQL which actually works perfectly but the addition of 171 + 0.18 only gives 171
IF I can get "171/18" instead of "171.18" as string then it'd also be great. (/ is just used as separator and not a divison sign)
Following is the code I written
Here,
(FAP.FQTY + FAP.QTY) = 7200,
PRD.CRT = 42
(values only for example)
select
case when PRD.CRT <> 0 then
case when (FAP.FQTY + FAP.QTY)/PRD.CRT <> FLOOR((FAP.FQTY + FAP.QTY)/PRD.CRT) then --DETERMINE WHETHER VALUE IS FLOAT OR NOT
(floor((FAP.FQTY + FAP.QTY)/PRD.CRT)) +
((FAP.FQTY + FAP.QTY) - floor((FAP.FQTY + FAP.QTY)/PRD.CRT) * PRD.CRT) /
POWER(10, len(floor((FAP.FQTY + FAP.QTY) - floor((FAP.FQTY + FAP.QTY)/PRD.CRT) * PRD.CRT)))
else
(FAP.FQTY + FAP.QTY)/PRD.CRT -- INTEGER
end
else
0
end
from FAP inner join PRD on FAP.Comp_Year = PRD.Comp_Year and
FAP.Comp_No = PRD.Comp_No and FAP.Prd_Code = PRD.Prd_Code
I got all the values correct till 171 + 0.1800 correct but after that I am only receiving 171 in the addition. I want exactly 171.18.
REASON FOR THIS CONFUSING CALCULATION
Its all about accounting
Suppose, a box(or a cartoon) has 42 nos. of items.
A person sends 7200 items. how many boxes he has to send?
So that will be (7200/42) = 171.4257.
But boxes cannot be cut (its whole number i.e 171).
so 171 * 42 ie 7182 items.
Remaining items = 7200 - 7182 = 18.
So answer is 171 boxes and 18 items.
In short 171.18 or "171/18"
Please help me with this..
Thank you in advance.
Recognise that you're not producing an actual numeric result, I'd describe it as unhealthy to try to keep it using such a datatype1.
This produces the strings you're seeking, if I've understood your requirement:
;With StartingPoint as (
select 7200 as Dividend, 42 as Divisor
)
select
CONVERT(varchar(10),Quotient) +
CASE WHEN Remainder > 0 THEN '.' + CONVERT(varchar(10),Remainder)
ELSE '' END as FinalString
from
StartingPoint
cross apply
(select Dividend/Divisor as Quotient, Dividend % Divisor as Remainder) t
(Not tested for negative values. Some adjustments may be required. Technically % computes the modulus rather than the remainder, etc)
1Because someone might try and add two of these values together and I doubt that produces a correct result, not even necessarily if using the same Divisor to compute both.
Just another idea about how to calculate it.
Simple calculate the whole boxes.
And concatinate a dot with the remaining items (using a modulus).
Wrapped it all up in a CASE WHEN (or IIF) to avoid the divide by zero.
Example snippet:
declare #TestTable table (FQTY numeric(18,2), QTY numeric(18,2), CRT numeric(18,0));
insert into #TestTable (FQTY,QTY,CRT) values
(5000, 2200, 42),
(5000, 2200, 0),
( 100, 200, 10);
select *,
(CASE
WHEN CRT>0
THEN CONCAT(CAST(FLOOR((FQTY+QTY)/CRT) as INT),'/',CAST((FQTY+QTY)%CRT as INT))
ELSE '0'
END) AS Boxes
from #TestTable;
Result:
FQTY QTY CRT Boxes
------- ------- --- ------
5000.00 2200.00 42 171/18
5000.00 2200.00 0 0
100.00 200.00 10 30/0
The CONCAT returns a varchar, and so does the CASE WHEN.
But you could wrap that CASE WHEN in a CAST.
You're getting an automatic type conversion from int to decimal(10,0) which is probably not what you want.
https://learn.microsoft.com/en-us/sql/t-sql/data-types/int-bigint-smallint-and-tinyint-transact-sql?view=sql-server-2017
Check out the "Caution" box.
If you want a specific amount of precision, you'll need to explicitly cast() the values to the desired data type.
if i understand your logic correctly you want the remainder of 7200 divide by 42 and the remainder is to divide by 100
declare
#dividend int = 7200,
#divisor int = 42
select (#dividend / #divisor)
+ convert(decimal(10,4),
(#dividend % #divisor) * 1.0 / power(10, len(#dividend % #divisor)))
EDIT: change to handle the 10^len(remainder)

Alternative query for calculating percentage

In SQL Server for calculating percentage I have a function like below:
CREATE FUNCTION [dbo].[fuGetPercentage] ( #part FLOAT, #total FLOAT )
RETURNS FLOAT
AS
BEGIN
DECLARE #Result FLOAT = 0, #Cent FLOAT = 100;
IF (isnull(#total, 0) != 0)
SET #Result = isnull(#part, 0) * #Cent / #total;
RETURN #Result
END
I wonder that is there any better alternative for that, with same checks and a better calculating percentage like below:
SELECT (CASE ISNULL(total, 0)
WHEN 0 THEN 0
ELSE ISNULL(part, 0) * 100 / total
END) as percentage
I want to use it directly after SELECT like above.
There is one issue with using functions such as ISNULL. The query will not use indexes in that case. If the beauty of the code isn't in the first place then you can do something like that:
SELECT
CASE WHEN total * part <> 0 /* will check that both total and part are not null and != 0*/
THEN part * 100 / total
ELSE 0
END AS percentage;
I use #DmitrijKultasev answer but now, I found that it has two problems:
Error on conversion because of the overflow of result of multiply.
Performance problem; because of that math multiply and its conversion.
So I change it to this:
SELECT
CASE
WHEN total <> 0 AND part <> 0 THEN -- This will return 0 for Null values
part * 100 / total
ELSE
0
END AS percentage;

Rounding-up TSQL

I gotta be missing something obvious.
select CEILING(85/30) = 2
85/30 = 2.83333
I want the value to be 3.
Shouldn't the CEILING function round up for me?
Try
SELECT CEILING(85.0/30)
And for comparison
SELECT 85.0 / 30, 85 / 30
The first example uses floats, the second uses ints, so the result is rounded before the ceiling function is hit. What you do is
SELECT CEILING(2)
Rather than
SELECT CEILING(2.833333)
Change it for :
select CEILING(85/30.0)
INT / INT yields an INT, so 85/30 rounds it down (FLOOR).
Use some typed-parameters, and you won't have to worry so much about how you enter the data. Here's a sam
DECLARE #int_num integer
DECLARE #int_dem integer
DECLARE #dec_num decimal(18,0)
DECLARE #dec_dem decimal(18,0)
SET #int_num = 85
SET #int_dem = 30
SET #dec_num = 85
SET #dec_dem = 30
SELECT CEILING(#int_num / #int_dem) AS int_div, CEILING(#dec_num / #dec_dem) AS dec_div
int_div | dec_div
----------------------
2 | 3

ASCII increment with defined range

Client wants to append a field with a literal increment based on a count.
The range goes from 'aa' to 'zz'.
'aa' represents a count of 1 and 'zz' represents the max value in the range: 676
I have sql that almost works but would appreciate an expert eye to get me over the last hurdle.
--Constants
DECLARE #START_ASCII INT = 97
DECLARE #ASCII_OFFSET INT = 1
DECLARE #ALPHABET_LETTER_COUNT INT = 26
--Variables
DECLARE #RecordCount INT = 0
DECLARE #FirstLetter VARCHAR(1) = NULL
DECLARE #SecondLetter VARCHAR(1) = NULL
SET #RecordCount = 1 --Range is 1 to 676 (e.g. 'aa' to 'zz')
SET #FirstLetter = CHAR(round(#RecordCount / #ALPHABET_LETTER_COUNT, 2, 1) + #START_ASCII)
SET #SecondLetter = CHAR((((#RecordCount - #ASCII_OFFSET) % #ALPHABET_LETTER_COUNT) + #START_ASCII))
SELECT #FirstLetter + #SecondLetter
The problem with the above sql involves the first letter. It works till the end of the alphabet is reached for the second letter. For example, at a count of 26, I expect 'az', but instead get 'bz'.
I want to keep the SQL small and tight (e.g. no CASE statements). Is there a small tweak I can make to the above code so that it will work?
Or, if there is just a smarter way to skin this cat, I'd like to know that.
I would think of this as computing the base-26 representation of #RecordCount-1 (range 0 to 675). Then map the two-digits of the base-26 number to the ASCII characters:
SET #FirstLetter = CHAR(floor((#RecordCount-1) / #ALPHABET_LETTER_COUNT) + #START_ASCII)
SET #SecondLetter = CHAR(((#RecordCount-1) % #ALPHABET_LETTER_COUNT) + #START_ASCII)

How to truncate decimal space in TSQL?

I am trying to get the size of database and wanna display it to the GUI. Thats what i am using
select
sum(((((CAST(saf.[size] as DECIMAL(18,4)) * 8192) /1024) /1024) /1024)) as 'Size'
from sys.sysdatabases sdb
inner join sys.sysaltfiles saf
on sdb.dbid = saf.dbid
where sdb.name = 'testDB'
Result is :-
3.8329467773437500000
But i want it to be trimmed or round up like this :-
3.84
Try rounding instead.
http://msdn.microsoft.com/en-us/library/ms175003.aspx
I didn't see your unique rounding issue. This looks interesting:
http://support.microsoft.com/kb/196652
CAST(
CEILING (
sum(((((CAST(saf.[size] as DECIMAL(18,4)) * 8192) /1024) /1024) /1024))
* 100)
AS decimal(18,2)
) / 100
3.8329467773437500000
-> 383.29467773437500000 (* 100)
-> 384.00000000... (CEILING)
-> 384.00 (to decimal 18, 2)
-> 3.84 (/ 100)

Resources