SQL Numerator from 0-Z - sql

Is there a simple an elegant way to create a numerator in SQL the do the following:
Three digit number
Each digit can can have a number from 0-Z : Min 000, Max ZZZ
for example let's take : 129, After increasing by 1, the new number will be 12A
When number is 15Z, after increasing by one it will turn into 160 and so on.
I can only use SQL, no code behind !!.
I only need an enumerator and not a conversion between bases like other have suggested.
Can someone help me write a UDF.
I got an excellent and elegant answer which I marked below.
Who ever marked my question as negative please reconsider because this is a real problem and not a theoratic one and it saved me a lot of workarounds.
Thanks in advance.

Produce cartesian and take the first that is greater then input value:
declare #v varchar(10) = '129'
;with cte as(select * from (values('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9')
,('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),('I'),('J'),('K')
,('L'),('M'),('N'),('O'),('P'),('Q'),('R'),('S'),('T'),('U'),('V')
,('W'),('X'),('Y'),('Z')) t(n))
select top 1 c1.n + c2.n + c3.n as n
from cte c1
cross join cte c2
cross join cte c3
where c1.n + c2.n + c3.n > #v
order by n

You should store the values numeric and then convert them when needed to your format.
Here is a script to add one to the strange format. The script is not checking for overflow nor invalid data in the original value:
DECLARE #original char(3) = '129'
DECLARE #val int =
CASE WHEN RIGHT(#original, 1) > '9' THEN ASCII(RIGHT(#original, 1)) - 55
ELSE RIGHT(#original, 1) END
+CASE WHEN SUBSTRING(#original, 2,1) > '9'
THEN ASCII(SUBSTRING(#original, 2,1)) - 55 ELSE SUBSTRING(#original, 2,1) END * 36
+CASE WHEN LEFT(#original, 1) > '9'
THEN ASCII(LEFT(#original, 1)) - 55 ELSE LEFT(#original, 1) END * 36 * 36
+1 -- increase 1
SELECT
CHAR(CASE WHEN #val / 36 / 36 > 9 THEN #val / 36 / 36 + 55
ELSE #val / 36 / 36+48 END)+
CHAR(CASE WHEN (#val / 36) % 36 > 9 THEN (#val / 36) % 36 + 55
ELSE (#val / 36) % 36+48 END)+
CHAR(CASE WHEN #val % 36 % 36 > 9 THEN #val % 36 % 36 + 55
ELSE #val % 36 % 36+48 END)
Result:
12A

I suggest you create this table in your DB with this query
;WITH Ch AS
( select i,C=CASE WHEN i<=10 THEN Char(47+i) ELSE CHAR(54+i) END FROM (SELECT TOP 36 row_number() over(order by object_id) i from sys.objects) t )
SELECT row_number() over(order by Ch.c,Ch2.c,Ch3.c) i,
Ch.c + Ch2.c + Ch3.c C INTO B36 FROM Ch CROSS JOIN Ch Ch2 CROSS JOIN Ch Ch3
So you can do indexes in the i & C columns
Then you do queries from this table for conversions with index seeking fastest speed and optimized as follows:
SELECT C FROM B36 WHERE i=3728
Reverse encoding with
SELECT i FROM B36 WHERE C='AG7'

Function that converts bigint to Base36
CREATE FUNCTION dbo.fnBase36
(
#Val BIGINT
)
RETURNS VARCHAR(13)
AS
BEGIN
DECLARE #Result VARCHAR(13) = ''
IF (#Val <= 0)
BEGIN
RETURN '0'
END
WHILE (#Val > 0)
BEGIN
SELECT #Result = CHAR(#Val % 36 + CASE WHEN #Val % 36 < 10 THEN 48 ELSE 55 END) + #Result,
#Val = FLOOR(#Val/36)
END
RETURN #Result
END
GO
select dbo.fnBase36(321)
--returns 8X

I can give you a converter like this:
char(48 + (i / (36 * 36)) + CASE WHEN (i / (36 * 36)) > 9 THEN 7 ELSE 0 END) +
char(48 + (i / 36) % 36 + CASE WHEN (i / 36) % 36 > 9 THEN 7 ELSE 0 END) +
char(48 + i % 36 + CASE WHEN i % 36 > 9 THEN 7 ELSE 0 END)
that can convert an int value to what you want.
[SQL Fiddle Demo]
Edit
I also can give you inversion of above converter like this:
(E.g.: #t varchar(max) = '12Z')
(ASCII(LEFT(#t, 1)) - 48 - CASE WHEN ASCII(LEFT(#t, 1)) > ASCII('9') THEN 7 ELSE 0 END) * 36 * 36 +
(ASCII(SUBSTRING(#t,2,1)) - 48 - CASE WHEN ASCII(SUBSTRING(#t,2,1)) > ASCII('9') THEN 7 ELSE 0 END) * 36 +
(ASCII(RIGHT(#t, 1)) - 48 - CASE WHEN ASCII(RIGHT(#t, 1)) > ASCII('9') THEN 7 ELSE 0 END)

Related

Get first n characters from a string write them and continue to get the next n characters and write them

I am trying to deal with some random numbers from a list.
What I am trying to achieve is to paste the numbers on multiple columns of max 35 char per column.
If there is a comma after, let's say char 32 and the next number has 6 char, I want to have the 32 char in column 1 and the next 35 chars from char 32 to in column 2, same condition, if there is a comma I would paste less.
I've only tried the cases until now, and I could get the 1st column, but I can't move to the next one.
declare #string varchar(max)
set #string= '2344,2343,5645465,546456,43645645,654656,5765765,6576467,7576576,35345435'
select
CASE WHEN (LEN(REPLACE(#string, ',', ';')) >= 35 ) THEN REVERSE(SUBSTRING(REVERSE(LEFT(REPLACE(#string, ',', ';'), 35)), CHARINDEX(';', REVERSE(LEFT(REPLACE(#string, ',', ';'), 35)))+1, 35)) ELSE REPLACE(#string, ',', ';') END as fact1,
'' as fact2,
'' as fact3,
'' as fact4
From string '2344,2343,5645465,546456,43645645,654656,5765765,6576467,7576576,35345435'
I would like:
column 1: 2344,2343,5645465,546456,43645645
column 2: 654656,5765765,6576467,7576576
column 3: 35345435
column 4:
Assuming SQL Server here, you could use a recursive CTE to first get the parts of the strings distributed on rows.
You need to split the string into a left and a right part. To get the proper position where to split take the whole 35 characters on the left, reverse it and look for the first comma in that reverse. That gives you the difference you need to correct the 35 with.
You can also have a running number in the CTE. So you can pick any number in a subquery in a SELECT without a FROM to get such a row as a column.
DECLARE #string varchar(max);
SET #string = '2344,2343,5645465,546456,43645645,654656,5765765,6576467,7576576,35345435';
WITH
cte
AS
(
SELECT 1 n,
left(#string, 35 - charindex(',', reverse(left(#string, 35)))) l,
CASE
WHEN len(#string) - 35 + charindex(',', reverse(left(#string, 35))) - 1 >= 0 THEN
right(#string, len(#string) - 35 + charindex(',', reverse(left(#string, 35))) - 1)
ELSE
''
END r
UNION ALL
SELECT n + 1 n,
left(r, 35 - charindex(',', reverse(left(r, 35)))) l,
CASE
WHEN len(r) - 35 + charindex(',', reverse(left(r, 35))) - 1 >= 0 THEN
right(r, len(r) - 35 + charindex(',', reverse(left(r, 35))) - 1)
ELSE
''
END r
FROM cte
WHERE len(r) > 0
)
SELECT (SELECT l
FROM cte
WHERE n = 1) [column 1],
(SELECT l
FROM cte
WHERE n = 2) [column 2],
(SELECT l
FROM cte
WHERE n = 3) [column 3],
(SELECT l
FROM cte
WHERE n = 4) [column 4];
db<>fiddle

SQL Server 2008 - Query to get result in fraction format

I have a table which contains data like this:
MinFormat(int) MaxFormat(int) Precision(nvarchar)
-2 3 1/2
The values in precision can be 1/2, 1/4, 1/8, 1/16, 1/32, 1/64 only.
Now I want result from query as -
-2
-3/2
-1
-1/2
0
1/2
1
3/2
2
5/2
3
Any query to get the result as follows?
Idea is to create result based onMinimum boundary (MinFomrat col value which is integer) to Maximum boundary (MaxFormat Col value which is integer) accordingly to the precision value.
Hence, in above example, value should start from -2 and generate the next values based on the precision value (1/2) till it comes to 3
Note this will only work for Precision 1/1, 1/2, 1/4, 1/8, 1/16, 1/32 and 1/64
DECLARE #t table(MinFormat int, MaxFormat int, Precision varchar(4))
INSERT #t values(-2, 3, '1/2')
DECLARE #numerator INT, #denominator DECIMAL(9,7)
DECLARE #MinFormat INT, #MaxFormat INT
-- put a where clause on this to get the needed row
SELECT #numerator = 1,
#denominator = STUFF(Precision, 1, charindex('/', Precision), ''),
#MinFormat = MinFormat,
#MaxFormat = MaxFormat
FROM #t
;WITH N(N)AS
(SELECT 1 FROM(VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))M(N)),
tally(N)AS(SELECT ROW_NUMBER()OVER(ORDER BY N.N)FROM N,N a,N b,N c,N d,N e,N f)
SELECT top(cast((#MaxFormat- #MinFormat) / (#numerator/#denominator) as int) + 1)
CASE WHEN val % 1 = 0 THEN cast(cast(val as int) as varchar(10))
WHEN val*2 % 1 = 0 THEN cast(cast(val*2 as int) as varchar(10)) + '/2'
WHEN val*4 % 1 = 0 THEN cast(cast(val*4 as int) as varchar(10)) + '/4'
WHEN val*8 % 1 = 0 THEN cast(cast(val*8 as int) as varchar(10)) + '/8'
WHEN val*16 % 1 = 0 THEN cast(cast(val*16 as int) as varchar(10)) + '/16'
WHEN val*32 % 1 = 0 THEN cast(cast(val*32 as int) as varchar(10)) + '/32'
WHEN val*64 % 1 = 0 THEN cast(cast(val*64 as int) as varchar(10)) + '/64'
END
FROM tally
CROSS APPLY
(SELECT #MinFormat +(N-1) *(#numerator/#denominator) val) x
Sorry, now I'm late, but this was my approach:
I'd wrap this in a TVF actually and call it like
SELECT * FROM dbo.FractalStepper(-2,1,'1/4');
or join it with your actual table like
SELECT *
FROM SomeTable
CROSS APPLY dbo.MyFractalSteller(MinFormat,MaxFormat,[Precision]) AS Steps
But anyway, this was the code:
DECLARE #tbl TABLE (ID INT, MinFormat INT,MaxFormat INT,Precision NVARCHAR(100));
--Inserting two examples
INSERT INTO #tbl VALUES(1,-2,3,'1/2')
,(2,-4,-1,'1/4');
--Test with example 1, just set it to 2 if you want to try the other example
DECLARE #ID INT=1;
--If you want to get your steps numbered, just de-comment the tree occurencies of "Step"
WITH RecursiveCTE as
(
SELECT CAST(tbl.MinFormat AS FLOAT) AS RunningValue
,CAST(tbl.MaxFormat AS FLOAT) AS MaxF
,1/CAST(SUBSTRING(LTRIM(RTRIM(tbl.Precision)),3,10) AS FLOAT) AS Prec
--,1 AS Step
FROM #tbl AS tbl
WHERE tbl.ID=#ID
UNION ALL
SELECT RunningValue + Prec
,MaxF
,Prec
--,Step + 1
FROM RecursiveCTE
WHERE RunningValue + Prec <= MaxF
)
SELECT RunningValue --,Step
,CASE WHEN CAST(RunningValue AS INT)<>RunningValue
THEN CAST(RunningValue / Prec AS VARCHAR(10)) + '/' + CAST(CAST(1/Prec AS INT) AS VARCHAR(MAX))
ELSE CAST(RunningValue AS VARCHAR(10))
END AS RunningValueFractal
FROM RecursiveCTE;
The result
Value ValueFractal
-2 -2
-1,5 -3/2
-1 -1
-0,5 -1/2
0 0
0,5 1/2
1 1
1,5 3/2
2 2
2,5 5/2
3 3
Mine is a bit different others. I perform the addition on fraction and at the end, simplified the fraction.
-- This solution uses CTE
-- it breaks the #min, #max number into fraction
-- perform the addition in terms of fraction
-- at result, it attemp to convert the fraction to simpliest form
declare #min int,
#max int,
#step varchar(10),
#step_n int, -- precision step numerator portion
#step_d int -- precision step denominator portion
select #min = -2,
#max = 3,
#step = '1/16'
select #step_n = left(#step, charindex('/', #step) - 1),
#step_d = stuff(#step, 1, charindex('/', #step), '')
; with rcte as
(
-- Anchor member
select n = #min, -- numerator
d = 1, -- denominator
v = convert(decimal(10,5), #min)
union all
-- Recursive member
select n = case when ( (r.n * #step_d) + (r.d * #step_n) ) % #step_d = 0
and (r.d * #step_d) % #step_d = 0
then ( (r.n * #step_d) + (r.d * #step_n) ) / #step_d
else (r.n * #step_d) + (r.d * #step_n)
end,
d = case when ( (r.n * #step_d) + (r.d * #step_n) ) % #step_d = 0
and (r.d * #step_d) % #step_d = 0
then (r.d * #step_d) / #step_d
else (r.d * #step_d)
end,
v = convert(decimal(10,5), ((r.n * #step_d) + (r.d * #step_n)) / (r.d * #step_d * 1.0))
from rcte r
where r.v < #max
)
select *,
fraction = case when n = 0
then '0'
when coalesce(d2, d) = 1
then convert(varchar(10), coalesce(n2, n))
else convert(varchar(10), coalesce(n2, n)) + '/' + convert(varchar(10), coalesce(d2, d))
end
from rcte r
cross apply -- use to simplify the fraction result
(
select n2 = case when n % 32 = 0 and d % 32 = 0 then n / 32
when n % 16 = 0 and d % 16 = 0 then n / 16
when n % 8 = 0 and d % 8 = 0 then n / 8
when n % 4 = 0 and d % 4 = 0 then n / 4
when n % 2 = 0 and d % 2 = 0 then n / 2
end,
d2 = case when n % 32 = 0 and d % 32 = 0 then d / 32
when n % 16 = 0 and d % 16 = 0 then d / 16
when n % 8 = 0 and d % 8 = 0 then d / 8
when n % 4 = 0 and d % 4 = 0 then d / 4
when n % 2 = 0 and d % 2 = 0 then d / 2
end
) s
order by v
option (MAXRECURSION 0)

How to create ordinal numbers (i.e. "1st" "2nd", etc.) in SQL Server

I recently responded to this question in the SSRS-2008 tag that required changing the day number in a date to the ordinal number (i.e. "1st", "2nd" instead of "1", "2"). The solution involved a VB.Net function. I'm curious how one would go about performing this task in SQL (t-sql and SQL Server in particular), or if there is some built in support.
So here is a scenario: say you have organized a footrace for 1000 runners and have the results in a table with the columns Name and Place (in normal numbers). You want to create a query that will display a user's name and their place in ordinal numbers.
Here's a scalable solution that should work for any number. I thought other's used % 100 for 11,12,13 but I was mistaken.
WITH CTE_Numbers
AS
(
SELECT 1 num
UNION ALL
SELECT num + 1
FROM CTE_Numbers
WHERE num < 1000
)
SELECT CAST(num AS VARCHAR(10))
+
CASE
WHEN num % 100 IN (11,12,13) THEN 'th' --first checks for exception
WHEN num % 10 = 1 THEN 'st'
WHEN num % 10 = 2 THEN 'nd'
WHEN num % 10 = 3 THEN 'rd'
ELSE 'th' --works for num % 10 IN (4,5,6,7,8,9,0)
END
FROM CTE_Numbers
OPTION (MAXRECURSION 0)
You can do that just as easily in SQL as in the app layer:
DECLARE #myDate DATETIME = '2015-05-21';
DECLARE #day INT;
SELECT #day = DAY(#myDate);
SELECT CASE WHEN #day IN ( 11, 12, 13 ) THEN CAST(#day AS VARCHAR(10)) + 'th'
WHEN #day % 10 = 1 THEN CAST(#day AS VARCHAR(10)) + 'st'
WHEN #day % 10 = 2 THEN CAST(#day AS VARCHAR(10)) + 'nd'
WHEN #day % 10 = 3 THEN CAST(#day AS VARCHAR(10)) + 'rd'
ELSE CAST(#day AS VARCHAR(10)) + 'th'
END
You could also put this in a scalar function if necessary.
EDIT
For your example, it would be:
SELECT Name ,
CASE WHEN Place IN ( 11, 12, 13 )
THEN CAST(Place AS VARCHAR(10)) + 'th'
WHEN Place % 10 = 1 THEN CAST(Place AS VARCHAR(10)) + 'st'
WHEN Place % 10 = 2 THEN CAST(Place AS VARCHAR(10)) + 'nd'
WHEN Place % 10 = 3 THEN CAST(Place AS VARCHAR(10)) + 'rd'
ELSE CAST(Place AS VARCHAR(10)) + 'th'
END AS Place
FROM FootRaceResults;
Be very afraid:
with
ArabicRomanConversions as (
select *
from ( values
( 0, '', '', '', '' ), ( 1, 'I', 'X', 'C', 'M' ), ( 2, 'II', 'XX', 'CC', 'MM' ), ( 3, 'III', 'XXX', 'CCC', 'MMM' ), ( 4, 'IV', 'XL', 'CD', '?' ),
( 5, 'V', 'L', 'D', '?' ), ( 6, 'VI', 'LX', 'DC', '?' ), ( 7, 'VII', 'LXX', 'DCC', '?' ), ( 8, 'VIII', 'LXXX', 'DCCC', '?' ), ( 9, 'IX', 'XC', 'CM', '?' )
) as Placeholder ( Arabic, Ones, Tens, Hundreds, Thousands )
),
OrdinalConversions as (
select *
from ( values
( 1, 'st' ), ( 2, 'nd' ), ( 3, 'rd' ), ( 11, 'th' ), ( 12, 'th' ), ( 13, 'th' )
) as Placeholder2 ( Number, Suffix )
),
Numbers as (
select 1 as Number
union all
select Number + 1
from Numbers
where Number < 3999 )
select Number as Arabic,
( select Thousands from ArabicRomanConversions where Arabic = Number / 1000 ) +
( select Hundreds from ArabicRomanConversions where Arabic = Number / 100 % 10 ) +
( select Tens from ArabicRomanConversions where Arabic = Number / 10 % 10 ) +
( select Ones from ArabicRomanConversions where Arabic = Number % 10 ) as Roman,
Cast( Number as VarChar(4) ) + Coalesce( (
select top 1 Suffix from OrdinalConversions where Number = Numbers.Number % 100 or Number = Numbers.Number % 10 order by Number desc ), 'th' ) as Ordinal
from Numbers option ( MaxRecursion 3998 );
You could use a case statement, I.e.,
UPDATE: Taking into account the teens, as mentioned by TPhe and refactored slightly.
SELECT
Name,
CASE
WHEN Place in(11, 12, 13) then CAST(Place as VARCHAR(20)) + 'th'
WHEN RIGHT(CAST(Place as VARCHAR(20)), 1) = '1' then CAST(Place as VARCHAR(20)) + 'st'
WHEN RIGHT(CAST(Place as VARCHAR(20)), 1) = '2' then CAST(Place as VARCHAR(20)) + 'nd'
WHEN RIGHT(CAST(Place as VARCHAR(20)), 1) = '3' then CAST(Place as VARCHAR(20)) + 'rd'
ELSE CAST(Place as VARCHAR(20)) + 'th'
END as Place
FROM
RunnerTable
DECLARE #Number int = 94
SELECT
CONVERT(VARCHAR(10),#NUMBER) + CASE WHEN #Number % 100 IN (11, 12, 13) THEN 'th'
ELSE
CASE #Number % 10
WHEN 1 THEN 'st'
WHEN 2 THEN 'nd'
WHEN 3 THEN 'rd'
ELSE 'th'
END
END
This Would be much better for any number
create Function dbo.fn_Numbers_Ordinal (#N as bigint) returns varchar(50)
as Begin
Declare #a as varchar(50)= CAST(#N AS VARCHAR(50))
return(
SELECT CAST(#N AS VARCHAR(50))
+
CASE
WHEN Right(#a,2)='11' or Right(#a,2)='12' or Right(#a,2)='13' Then 'th'
WHEN #N % 10 = 1 THEN 'st'
WHEN #N % 10 = 2 THEN 'nd'
WHEN #N % 10 = 3 THEN 'rd'
ELSE 'th' --for #N % 10 IN (4,5,6,7,8,9,0)
END
)
end
Just figured I would add onto the various options. Here's a one-liner. I left this as a comment about a year ago. But someone suggested I submit it as an answer. So here ya go:
SELECT OrdinalRank = CONCAT(num, IIF(num % 100 IN (11,12,13),'th',COALESCE(CHOOSE(num % 10,'st','nd','rd'),'th')))
FROM (
VALUES (1),(2),(3),(4),(5),(10),(11),(20),(21),(22),(23),(24),(101),(102),(103)
) x(num)
--Result:
--1st
--2nd
--3rd
--4th
--5th
--10th
--11th
--20th
--21st
--22nd
--23rd
--24th
--101st
--102nd
--103rd
This takes advantage of the IIF and CHOOSE functions, which are only available in SQL 2012+.
DECLARE #Number int = 113,
#Superscript int
IF #Number IS NOT NULL
BEGIN
IF LEN(#Number) >= 2
SELECT #Superscript = RIGHT(#Number, 2)
ELSE
SELECT #Superscript = RIGHT(#Number, 1)
SELECT #Number as Number,
CASE WHEN #Superscript in (11,12,13) THEN 'th'
ELSE CASE WHEN #Superscript = 1 THEN 'st'
WHEN #Superscript = 2 THEN 'nd'
WHEN #Superscript = 3 THEN 'rd'
ELSE 'th'
END
END as Superscript
END ELSE
SELECT 0 as Number, 'th' as Superscript
Another option to solve this with the FORMAT function (also you can display month names in other languages):
;WITH cte AS (
SELECT 1 AS dayordinal ,'st' AS suffix
UNION
SELECT 2 AS dayordinal ,'nd' AS suffix
UNION
SELECT 3 AS dayordinal ,'rd' AS suffix
)
, YourTable AS --this is just for example
(SELECT CAST('1/1/2022' AS DATE) DateColumn
UNION
SELECT CAST('1/14/2022' AS DATE) DateColumn
UNION
SELECT CAST('4/4/2022' AS DATE) DateColumn
UNION
SELECT CAST('2/2/2022' AS DATE) DateColumn
UNION
SELECT CAST('3/13/2022' AS DATE) DateColumn
)
SELECT CAST(DATEPART(DAY, DateColumn) AS NVARCHAR(2))+ISNULL(c.suffix, 'th')+' '+ FORMAT(DateColumn, 'MMMM yyyy', 'fr-FR')
FROM YourTable t
LEFT JOIN cte c ON c.dayordinal=RIGHT(DATEPART(DAY, DateColumn),1)
Use the SSRS expression below:
= DAY(Globals!ExecutionTime) &
SWITCH(
DAY(Globals!ExecutionTime)= 1 OR DAY(Globals!ExecutionTime) = 21 OR DAY(Globals!ExecutionTime)=31, "st",
DAY(Globals!ExecutionTime)= 2 OR DAY(Globals!ExecutionTime) = 22 , "nd",
DAY(Globals!ExecutionTime)= 3 OR DAY(Globals!ExecutionTime) = 23 , "rd",
true, "th"
)
This is easy to implement and works well.
Public Function OrdinalNumberSuffix(ByVal InNumber As Integer) As String
Dim StrNumber As String, _
Digit As Byte, _
Suffix As String
StrNumber = Trim(Str(InNumber))
If Val(StrNumber) > 3 And Val(StrNumber) < 14 Then
Digit = Val(Right(StrNumber, 2))
Else
Digit = Val(Right(StrNumber, 1))
End If
Select Case Digit
Case 1: Suffix = "st"
Case 2: Suffix = "nd"
Case 3: Suffix = "rd"
Case Else: Suffix = "th"
End Select
OrdinalNumberSuffix = " " & StrNumber & Suffix & " "
End Function

Cap field value in SELECT

I am trying to cap particular fields so that they don't exceed a particular value.
For example, something like this would suffice, where I can specify that a field should not exceed 8:
SELECT (
cap(t.MondayHrs,8)
+ cap(t.TuesdayHrs,8)
+ cap(t.WednesdayHrs,8)
+ cap(t.ThursdayHrs,8)
+ cap(t.FridayHrs,8)
) as TotalHours
If MondayHrs = 7, then it should be added to TotalHours as 7.
If MondayHrs = 10, then it should be added to TotalHours as 8 (my capped value)
Is there anything built into T-SQL that could facilitate this?
create function Cap (#Value float,#maxValue float) Returns float
as
begin
Declare #Result float
if #Value > #maxValue select #Result=#Maxvalue else select #Result=#Value
Return #Result
end;
usage
Select dbo.Cap(1,10),dbo.Cap(11,10)
Try...
select least(t.MondayHrs,8)
+ least(t.TuesdayHrs,8)
+ least(t.WednesdayHrs,8)
+ least(t.ThursdayHrs,8)
+ least(t.FridayHrs,8)
) as TotalHours
An alternate idea would be to use CASE. For example:
SELECT (
(CASE WHEN t.MondayHrs > 8 THEN 8 ELSE t.MondayHrs END)
+ (CASE WHEN t.TuesdayHrs > 8 THEN 8 ELSE t.TuesdayHrs END)
) as TotalHours
You can write a function for that like MySQL GREATEST.
Then you could do something like
select greatest(some_col, 8) +
greatest(other_col, 8) +
...
from your_table

TSQL round number and check in which group it is

I have a quite simple task:
I must check in wchich group my float is.
Here are my groups:
0-30 display "(0-30)"
30-40 display "(0-30)"
40-50 display "(0-30)"
50-60 display "(0-30)"
etc
I have created a simple script:
DECLARE #num FLOAT
SET #num = 42.5;
SELECT CASE WHEN #num<=30 THEN '(0-30)'
ELSE '('+convert(VARCHAR,convert(INT,round((#num/10),0))*10)+'-'+convert(VARCHAR,convert(INT,round(((#num+10)/10),0))*10)+')'
END
I think it is a little lame, so if anyone could help me out with creating a better solution :)
Thanks for any advice :)
Use:
DECLARE #num FLOAT
SET #num = 311.2;
SELECT
CASE
WHEN #num <= 30
THEN '(0-30)'
ELSE '(' + cast(cast(#num AS INT) / 10 * 10 AS VARCHAR) + '-' + cast(cast(#num AS INT) / 10 * 10 + 10 AS VARCHAR) + ')' END
Or you can use: (to get rid of the CASE statement and get a more readable look, IMO)
declare #num float = 156
select
'(' + convert(varchar, lowLimit) + ' - ' + convert(varchar, highLimit) + ')'
from
(
select
0 as lowLimit,
30 as highLimit
where
#num <= 30
union all
select
floor(#num/10)*10,
ceiling(#num/10)*10
where
#num > 30
) limits