DB2 SELECT which sums two columns and handles null values - select

Let's say I have flowing table MY_TABLE with columns A and B:
NULL, NULL
NULL, 1
1, NULL,
1, 1
0, 0
What I need is a select which returns:
NULL
1
1
2
0
SELECT A + B
FROM MY_TABLE
will result in:
NULL
NULL
NULL
2
0
Currently, I have written new MY_SUM function so I can have:
SELECT MY_SUM(A, B)
FROM MY_TABLE
CREATE FUNCTION MY_SUM(IN decimalNumber1 DECIMAL(20, 2), IN decimalNumber2 DECIMAL(20, 2))
RETURNS DECIMAL(20, 2)
BEGIN
DECLARE decimalSum DECIMAL(20, 2);
IF decimalNumber1 IS NOT NULL THEN
SET decimalSum = decimalNumber1;
END IF;
IF decimalNumber2 IS NOT NULL THEN
IF decimalSum IS NULL THEN
SET decimalSum = decimalNumber2;
ELSE
SET decimalSum = decimalSum + decimalNumber2;
END IF;
END IF;
RETURN decimalSum;
END
but I was wondering if there is a better out-of-the-box way for doing this?

Try this:
select case when a is null and b is null then null else coalesce(a,0)+coalesce(b,0) end from my_table
or
"select case when coalesce(a,b) is null then null else coalesce(a,0)+coalesce(b,0) end from my_table
There are many other ways to do it.

The following expression works in your case:
COALESCE(A, B) - COALESCE(A, B) + COALESCE(A, 0) + COALESCE(B, 0)

COALESCE will do the job - your problem is not fully described but check out this
WITH temp (a, b) AS (
VALUES (NULL, NULL), (NULL, 1), (1, NULL), (1, 1)
)
SELECT COALESCE(a,0) + COALESCE(b,0)
FROM temp
WHERE COALESCE(a,0) + COALESCE(b,0) <> 0

There is not a built-in way to transparently interpret NULLs as 0s.
Probably the closest you can get is with a function like this
CREATE OR REPLACE FUNCTION MY_SUM(
n1 DECFLOAT DEFAULT NAN
,n2 DECFLOAT DEFAULT NAN
,n3 DECFLOAT DEFAULT NAN
,n4 DECFLOAT DEFAULT NAN
,n5 DECFLOAT DEFAULT NAN
) RETURNS DECFLOAT
RETURN
CASE WHEN COALESCE(NULLIF(n1,NAN),NULLIF(n2,NAN)) IS NOT NULL THEN
+ COALESCE(NULLIF(n1,NAN),0)
+ COALESCE(NULLIF(n2,NAN),0)
+ COALESCE(NULLIF(n3,NAN),0)
+ COALESCE(NULLIF(n4,NAN),0)
+ COALESCE(NULLIF(n5,NAN),0)
END
which you can extend to support more columns as needed
SELECT MY_SUM(a,b) AS SUM
FROM TABLE(VALUES (NULL, NULL), (NULL, 1), (1, NULL), (1, 1)) T(a,b)
would then return
S
-
1
1
2
Note The function could be simpler if you create one function for each number of parameters you want to sum, but the single function with DEFAULTs is neater

Related

multiply previous row's results for all rows

How can I dynamically multiply the previous row's results:
row A col_3 = if (row A col_1 <= 1 then 1), else (1 * col_2)
row B col_3 = if (row B col_1 <= 1 then 1), else (row A * col_2)
row C col_3 = if (row C col_1 <= 1 then 1), else (row B * col_2)
I've attempted this in Postgres. Here's
sum (
case
when col_1 <= 1 then 1
else (lag(col_3) over (...)) * col_2 <-- I'm aware you cannot use a lag function within a sum/window function
end
) over (order by ...) as col_3
Note: I've asked a similar question here (thanks #Bergi!), but I'm not sure how to implement that answer for this purpose.
EDIT:
Logic:
if (previous_interval is null) previous_interval = 1
if (curr_repetition = 1) interval = 1
else if (curr_repetition = 2) interval = 6
else interval = previous_interval * easiness

Why didn't the query return any rows?

Why didn't the query return any rows?
SELECT 1 FROM sysibm.sysdummy1 WHERE 1 NOT IN (2, NULL)
1 NOT IN (2, NULL) is equal to 1 <> 2 AND 1 <> NULL
The result of 1 <> NULL is UNKNOWN, so, the result of the original expression is:
TRUE AND UNKNOWN which is UNKNOWN.
But you get the result for rows, where an expression in WHERE evaluates as TRUE only.

SQL Select where exclusive Or /Case

I need a query based on an exclusive Or statement for this I try using the case but I won't get a result in case of Null...
...
and b.[U_Periode] = CASE
when (b.U_Periode= #period) then #period
when (b.U_Periode is NULL ) then null
end
...
The Case that won't be catched is... if B.U_Status is null and b.U_Periode is null.
If the var Periode match the Value and the U_Status = 0 or 1
the only way getting this working for me was this:
...
and
ISNULL( b.[U_Status],'0') = CASE
when (b.U_Status= '1') then '1'
when (isnull( b.U_Status,'0')= '0') then '0'
end
and
ISNULL (b.[U_Periode],'01.01.1901') = CASE
when (b.U_Periode= #period) then #period
when (ISNULL (b.U_Periode,'01.01.1901') = '01.01.1901' ) then '01.01.1901'
end
are there any other better solutions for this?
Best regards
Oliver
Okay... here is my Problem
Table1
InsID ContractID
1 1
2 1
Table2
ID insid Period Status Count
1 1 null null 100
2 1 30.09.2015 1 500
3 2 null null 100
4 2 30.09.2015 1 500
Case '31.08.2015'
in total Value should be 200
in case of '30.09.2015'
the Value should be 1.000
XOR /OR will do the same in this case.
Value case '31.08.2015' = 200
value Case ' 30.09.2015 = 2200
So this is somesing like a subquery
left join (
[dbo].[Table2]b
inner join [dbo].[Table 3]K on k.DocEntry = b.DocEntry and CAST( k.U_CSetID as int) >0
)
on b.[U_InsID] in(select... but here I should have an if statement...
If there are results matching the Date join this
If not than join the result NULL is matching to periode...
Okay.. here is the complete query
the Table2 with the Date of 31.08.2015 should have one Record that include
B_STATUS = Null and B.Preiode = null and there is no available record with the U_Periode '31.08.2015' and a Staus ...
with a date of 30.09.2015
there is a Record matching U_Period = '30.09.2015' in this case the Record with U_Period=null should not effect the result...
Declare #period as varchar(20)= '31-08-2015 00:00:00'
declare #Customer as Varchar(15)='12345'
declare #Contract as varchar(30) = '123'
declare #test as varchar(1) = null
select SUM(cast(K.U_Count as decimal))as counter, K.U_CounterTyp
from [dbo].[Table1] a
left join (
[dbo].[Table2]b
inner join [dbo].[Table 3]K on k.DocEntry = b.DocEntry and CAST( k.U_CSetID as int) >0
)
on b.[U_InsID]=a.[insID] and b.[U_ObjectType]in ('5','1') and
ISNULL( b.[U_Status],'0') = CASE
when (b.U_Status= '1') then '1'
when (isnull( b.U_Status,'0')= '0') then '0'
end
and
ISNULL (b.[U_Periode],'01.01.1901') = CASE
when (b.U_Periode= #period) then #period
when (ISNULL (b.U_Periode,'01.01.1901') = '01.01.1901' ) then '01.01.1901'
end
where a.[customer] =#Customer and a.[Status]='A' and a.[U_ContrCount]='1'
and a.[manufSN] in(
select c.[ManufSN] from [dbo].[Table4] c
inner join [dbo].[OCTR]d on d.[ContractID] = c.[ContractID]
where c.[ManufSN]=a.[manufSN]
and d.[CstmrCode] = a.[customer] and d.[ContractID]=#Contract
)
group by K.U_CounterTyp
you must use the "^" operand, this is XOR operand in TSQL
expression ^ expression
the expression must return or 0 or 1...
stupid example:
WHERE (name like "stackoverflow") ^ (age > 10)
font: https://msdn.microsoft.com/en-us/library/ms190277(v=sql.105).aspx
Update for your check
WHERE (CONVERT(VARCHAR(10), a.[U_Periode], 104) = '30.08.2015') != (a.U_Periode IS NULL)
Olay here is my funktion that chek either a Date Result is there or not.
The only thing is, that the performance is not the best if I run hundreths of sentences ... foreach record (up to app. 1000) I need to query each subtable... and there are many many records in...
Anyway this is the function
CREATE FUNCTION fn_GetInsCounters(#InsId as Varchar(30), #Date as datetime)
returns datetime
as
begin
declare #count as int = 0
declare #Retruns as Datetime
set #count =
(
select count( b.Docentry)
from [dbo].[Table2]b
where b.U_Insid =#InsID
and b.U_Status <> '2'
and b.[U_ObjectType]in ('5','1')
and b.U_Periode=#Date
)
if(#count>0)
begin
set #Retruns = #date
end
else
begin
set #Retruns = '01.01.1901'
end
return #Retruns
end
if anyone gets a better idea???
Best regards
Oliver

Subnet (or CIDR) IP control at T-SQL

I don't know how to exactly explain, but there is a problem about selecting and comparing query IP subnet. For example, there is a list for IP address and I have another CIDR/subnet mask list (X.X.X.0/24 etc). How can I learn that each IP address in first list is in CIDR/subnet mask list via T-SQL?
For example:
IP: 172.28.112.23 -> false
IP: 172.28.111.33 -> true
IP List Output:
SubNet Output:
You want to do exactly what a computer would do to determine if an ip address is in a subnet- ie:
1) convert the network address, subnet mask and test address to binary.
2) Check if (Network Address & Subnet Mask) = (Test Address & Subnet mask)
(& represents bitwise AND)
If this comparison is true the test address is within the subnet
The key to understanding this is to realise that IP addresses (and subnet masks) are just 32 bit numbers.
A bitwise and between 2 32 bit numbers creates a new 32 bit number with a 1 in the position where there was a 1 in both of the 2 numbers being compared, and a 0 otherwise.
EG: 1010 & 1100 = 1000 because the first digit is 1 in both numbers (yielding a 1 in the result for the first digit), but the 2nd 3rd and 4th digits are not (so give 0 in the result for the 2nd 3rd and 4th digits).
SQL Server cannot do a bitwise and between 2 binary numbers unfortunately, but it works fine between decimal representations (ie when converted to BIGINT datatype).
Therefore I'd propose you create a function that converts your IP addresses to BIGINT datatype firstly
CREATE FUNCTION dbo.fnIPtoBigInt
(
#Ipaddress NVARCHAR(15) -- should be in the form '123.123.123.123'
)
RETURNS BIGINT
AS
BEGIN
DECLARE #part1 AS NVARCHAR(3)
DECLARE #part2 AS NVARCHAR(3)
DECLARE #part3 AS NVARCHAR(3)
DECLARE #part4 AS NVARCHAR(3)
SELECT #part1 = LEFT(#Ipaddress, CHARINDEX('.',#Ipaddress) - 1)
SELECT #Ipaddress = SUBSTRING(#Ipaddress, LEN(#part1) + 2, 15)
SELECT #part2 = LEFT(#Ipaddress, CHARINDEX('.',#Ipaddress) - 1)
SELECT #Ipaddress = SUBSTRING(#Ipaddress, LEN(#part2) + 2, 15)
SELECT #part3 = LEFT(#Ipaddress, CHARINDEX('.',#Ipaddress) - 1)
SELECT #part4 = SUBSTRING(#Ipaddress, LEN(#part3) + 2, 15)
DECLARE #ipAsBigInt AS BIGINT
SELECT #ipAsBigInt =
(16777216 * (CAST(#part1 AS BIGINT)))
+ (65536 * (CAST(#part2 AS BIGINT)))
+ (256 * (CAST(#part3 AS BIGINT)))
+ (CAST(#part4 AS BIGINT))
RETURN #ipAsBigInt
END
GO
Then you can easily implement a function to test if an address is in a subnet:
CREATE FUNCTION dbo.fnIsIpaddressInSubnet
(
#networkAddress NVARCHAR(15), -- 'eg: '192.168.0.0'
#subnetMask NVARCHAR(15), -- 'eg: '255.255.255.0' for '/24'
#testAddress NVARCHAR(15) -- 'eg: '192.168.0.1'
)
RETURNS BIT AS
BEGIN
RETURN CASE WHEN (dbo.fnIPtoBigInt(#networkAddress) & dbo.fnIPtoBigInt(#subnetMask))
= (dbo.fnIPtoBigInt(#testAddress) & dbo.fnIPtoBigInt(#subnetMask))
THEN 1 ELSE 0 END
END
To make this a bit easier for you you'll probably want a function that can convert '/24' to a BigInt too.
'/24' is a shorthand way of writing 255.255.255.0 - ie a 32bit number with the first 24bits set to 1 (and the remaining 8 bits set to 0)
CREATE FUNCTION dbo.fnSubnetBitstoBigInt
(
#SubnetBits TINYINT -- max = 32
)
RETURNS BIGINT
AS
BEGIN
DECLARE #multiplier AS BIGINT = 2147483648
DECLARE #ipAsBigInt AS BIGINT = 0
DECLARE #bitIndex TINYINT = 1
WHILE #bitIndex <= #SubnetBits
BEGIN
SELECT #ipAsBigInt = #ipAsBigInt + #multiplier
SELECT #multiplier = #multiplier / 2
SELECT #bitIndex = #bitIndex + 1
END
RETURN #ipAsBigInt
END
GO
If you create the following additional function the conversion becomes easy
CREATE FUNCTION dbo.fnIsIpaddressInSubnetShortHand
(
#network NVARCHAR(18), -- 'eg: '192.168.0.0/24'
#testAddress NVARCHAR(15) -- 'eg: '192.168.0.1'
)
RETURNS BIT AS
BEGIN
DECLARE #networkAddress NVARCHAR(15)
DECLARE #subnetBits TINYINT
SELECT #networkAddress = LEFT(#network, CHARINDEX('/', #network) - 1)
SELECT #subnetBits = CAST(SUBSTRING(#network, LEN(#networkAddress) + 2, 2) AS TINYINT)
RETURN CASE WHEN (dbo.fnIPtoBigInt(#networkAddress) & dbo.fnSubnetBitstoBigInt(#subnetBits))
= (dbo.fnIPtoBigInt(#testAddress) & dbo.fnSubnetBitstoBigInt(#subnetBits))
THEN 1 ELSE 0 END
END
i.e.
SELECT dbo.fnIsIpaddressInSubnetShorthand('192.168.2.0/24','192.168.3.91') -- returns 0
SELECT dbo.fnIsIpaddressInSubnetShorthand('192.168.2.0/24','192.168.2.91') -- returns 1
This is not an answer in itself, but a way to make one of the functions in James S answer easier to read and possibly more efficient.
SQL Server has a function to handle getting parts from database object names. Those names are 4 parts [Server].[Database].[Schema].[Object]. So the following allows you to get the schema name. The index works from the right
SELECT PARSENAME('[myServer].[master].[sys].[objects]', 2)
There's nothing to say you can't use that for an IP address. And as it's so fundamental to how SQL operates I assume it has been hella optimised.
CREATE FUNCTION dbo.fnIPtoBigInt
(
#Ipaddress NVARCHAR(15) -- should be in the form '123.123.123.123'
)
RETURNS BIGINT
AS
BEGIN
DECLARE #ipAsBigInt AS BIGINT
SELECT #ipAsBigInt =
(16777216 * (CAST(PARSENAME(#Ipaddress, 4) AS BIGINT)))
+ (65536 * (CAST(PARSENAME(#Ipaddress, 3) AS BIGINT)))
+ (256 * (CAST(PARSENAME(#Ipaddress, 2) AS BIGINT)))
+ (CAST(PARSENAME(#Ipaddress, 1) AS BIGINT))
RETURN #ipAsBigInt
END
GO
Complete solution
CREATE
OR ALTER FUNCTION dbo.IPv4SubnetContainsIPAddress (
#net AS VARCHAR(15),
#mask AS VARCHAR(15),
#ip AS VARCHAR(15)
) RETURNS tinyint AS BEGIN DECLARE #result AS tinyint IF LEN(#mask) <= 2
SELECT
#mask = m
FROM
(
VALUES
(0, '0.0.0.0'),
(1, '128.0.0.0'),
(2, '192.0.0.0'),
(3, '224.0.0.0'),
(4, '240.0.0.0'),
(5, '248.0.0.0'),
(6, '252.0.0.0'),
(7, '254.0.0.0'),
(8, '255.0.0.0'),
(9, '255.128.0.0'),
(10, '255.192.0.0'),
(11, '255.224.0.0'),
(12, '255.240.0.0'),
(13, '255.248.0.0'),
(14, '255.252.0.0'),
(15, '255.254.0.0'),
(16, '255.255.0.0'),
(17, '255.255.128.0'),
(18, '255.255.192.0'),
(19, '255.255.224.0'),
(20, '255.255.240.0'),
(21, '255.255.248.0'),
(22, '255.255.252.0'),
(23, '255.255.254.0'),
(24, '255.255.255.0'),
(25, '255.255.255.128'),
(26, '255.255.255.192'),
(27, '255.255.255.224'),
(28, '255.255.255.240'),
(29, '255.255.255.248'),
(30, '255.255.255.252'),
(31, '255.255.255.254'),
(32, '255.255.255.255')
) AS o (i, m)
WHERE
i = #mask
SELECT
#result = IIF(Count(*) = 4, 1, 0)
FROM
(
SELECT
*,
IIF(
o_ip BETWEEN o_subnet
AND o_broadcast,
1,
0
) AS eq
FROM
(
SELECT
*,
o_net & o_mask AS o_subnet,
o_net | (255 - o_mask) AS o_broadcast
FROM
(
SELECT
o_net,
o_mask,
o_ip
FROM
(
VALUES
(1, CAST(PARSENAME(#net, 4) AS INTEGER)),
(2, CAST(PARSENAME(#net, 3) AS INTEGER)),
(3, CAST(PARSENAME(#net, 2) AS INTEGER)),
(4, CAST(PARSENAME(#net, 1) AS INTEGER))
) AS c1 (i, o_net)
LEFT JOIN (
SELECT
i,
o_mask
FROM
(
VALUES
(1, CAST(PARSENAME(#mask, 4) AS INTEGER)),
(2, CAST(PARSENAME(#mask, 3) AS INTEGER)),
(3, CAST(PARSENAME(#mask, 2) AS INTEGER)),
(4, CAST(PARSENAME(#mask, 1) AS INTEGER))
) AS c2 (i, o_mask)
) AS c2 ON c1.i = c2.i
LEFT JOIN (
SELECT
i,
o_ip
FROM
(
VALUES
(1, CAST(PARSENAME(#ip, 4) AS INTEGER)),
(2, CAST(PARSENAME(#ip, 3) AS INTEGER)),
(3, CAST(PARSENAME(#ip, 2) AS INTEGER)),
(4, CAST(PARSENAME(#ip, 1) AS INTEGER))
) AS c3 (i, o_ip)
) AS c3 ON c1.i = c3.i
) AS t
) AS t
) AS t
WHERE
eq = 1 RETURN #result END
GO
SELECT
dbo.IPv4SubnetContainsIPAddress('192.168.64.0', '255.255.224.0', '192.168.40.1') -- returns 0
SELECT
dbo.IPv4SubnetContainsIPAddress('192.168.64.0', '19', '192.168.40.1') -- returns 0
SELECT
dbo.IPv4SubnetContainsIPAddress('192.168.64.0', '255.255.192.0', '192.168.80.1') -- returns 1
SELECT
dbo.IPv4SubnetContainsIPAddress('192.168.64.0', '18', '192.168.80.1') -- returns 1

Getting the minimum of two values in SQL

I have two variables, one is called PaidThisMonth, and the other is called OwedPast. They are both results of some subqueries in SQL. How can I select the smaller of the two and return it as a value titled PaidForPast?
The MIN function works on columns, not variables.
SQL Server 2012 and 2014 supports IIF(cont,true,false) function. Thus for minimal selection you can use it like
SELECT IIF(first>second, second, first) the_minimal FROM table
While IIF is just a shorthand for writing CASE...WHEN...ELSE, it's easier to write.
The solutions using CASE, IIF, and UDF are adequate, but impractical when extending the problem to the general case using more than 2 comparison values. The generalized
solution in SQL Server 2008+ utilizes a strange application of the VALUES clause:
SELECT
PaidForPast=(SELECT MIN(x) FROM (VALUES (PaidThisMonth),(OwedPast)) AS value(x))
Credit due to this website:
http://sqlblog.com/blogs/jamie_thomson/archive/2012/01/20/use-values-clause-to-get-the-maximum-value-from-some-columns-sql-server-t-sql.aspx
Use Case:
Select Case When #PaidThisMonth < #OwedPast
Then #PaidThisMonth Else #OwedPast End PaidForPast
As Inline table valued UDF
CREATE FUNCTION Minimum
(#Param1 Integer, #Param2 Integer)
Returns Table As
Return(Select Case When #Param1 < #Param2
Then #Param1 Else #Param2 End MinValue)
Usage:
Select MinValue as PaidforPast
From dbo.Minimum(#PaidThisMonth, #OwedPast)
ADDENDUM:
This is probably best for when addressing only two possible values, if there are more than two, consider Craig's answer using Values clause.
For SQL Server 2022+ (or MySQL or PostgreSQL 9.3+), a better way is to use the LEAST and GREATEST functions.
SELECT GREATEST(A.date0, B.date0) AS date0,
LEAST(A.date1, B.date1, B.date2) AS date1
FROM A, B
WHERE B.x = A.x
With:
GREATEST(value [, ...]) : Returns the largest (maximum-valued) argument from values provided
LEAST(value [, ...]) Returns the smallest (minimum-valued) argument from values provided
Documentation links :
MySQL http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html
Postgres https://www.postgresql.org/docs/current/functions-conditional.html
SQL Server https://learn.microsoft.com/en-us/sql/t-sql/functions/logical-functions-least-transact-sql
I just had a situation where I had to find the max of 4 complex selects within an update.
With this approach you can have as many as you like!
You can also replace the numbers with aditional selects
select max(x)
from (
select 1 as 'x' union
select 4 as 'x' union
select 3 as 'x' union
select 2 as 'x'
) a
More complex usage
#answer = select Max(x)
from (
select #NumberA as 'x' union
select #NumberB as 'x' union
select #NumberC as 'x' union
select (
Select Max(score) from TopScores
) as 'x'
) a
I'm sure a UDF has better performance.
Here is a trick if you want to calculate maximum(field, 0):
SELECT (ABS(field) + field)/2 FROM Table
returns 0 if field is negative, else, return field.
Use a CASE statement.
Example B in this page should be close to what you're trying to do:
http://msdn.microsoft.com/en-us/library/ms181765.aspx
Here's the code from the page:
USE AdventureWorks;
GO
SELECT ProductNumber, Name, 'Price Range' =
CASE
WHEN ListPrice = 0 THEN 'Mfg item - not for resale'
WHEN ListPrice < 50 THEN 'Under $50'
WHEN ListPrice >= 50 and ListPrice < 250 THEN 'Under $250'
WHEN ListPrice >= 250 and ListPrice < 1000 THEN 'Under $1000'
ELSE 'Over $1000'
END
FROM Production.Product
ORDER BY ProductNumber ;
GO
This works for up to 5 dates and handles nulls. Just couldn't get it to work as an Inline function.
CREATE FUNCTION dbo.MinDate(#Date1 datetime = Null,
#Date2 datetime = Null,
#Date3 datetime = Null,
#Date4 datetime = Null,
#Date5 datetime = Null)
RETURNS Datetime AS
BEGIN
--USAGE select dbo.MinDate('20120405',null,null,'20110305',null)
DECLARE #Output datetime;
WITH Datelist_CTE(DT)
AS (
SELECT #Date1 AS DT WHERE #Date1 is not NULL UNION
SELECT #Date2 AS DT WHERE #Date2 is not NULL UNION
SELECT #Date3 AS DT WHERE #Date3 is not NULL UNION
SELECT #Date4 AS DT WHERE #Date4 is not NULL UNION
SELECT #Date5 AS DT WHERE #Date5 is not NULL
)
Select #Output=Min(DT) FROM Datelist_CTE;
RETURN #Output;
END;
Building on the brilliant logic / code from mathematix and scottyc, I submit:
DECLARE #a INT, #b INT, #c INT = 0;
WHILE #c < 100
BEGIN
SET #c += 1;
SET #a = ROUND(RAND()*100,0)-50;
SET #b = ROUND(RAND()*100,0)-50;
SELECT #a AS a, #b AS b,
#a - ( ABS(#a-#b) + (#a-#b) ) / 2 AS MINab,
#a + ( ABS(#b-#a) + (#b-#a) ) / 2 AS MAXab,
CASE WHEN (#a <= #b AND #a = #a - ( ABS(#a-#b) + (#a-#b) ) / 2)
OR (#a >= #b AND #a = #a + ( ABS(#b-#a) + (#b-#a) ) / 2)
THEN 'Success' ELSE 'Failure' END AS Status;
END;
Although the jump from scottyc's MIN function to the MAX function should have been obvious to me, it wasn't, so I've solved for it and included it here: SELECT #a + ( ABS(#b-#a) + (#b-#a) ) / 2. The randomly generated numbers, while not proof, should at least convince skeptics that both formulae are correct.
Use a temp table to insert the range of values, then select the min/max of the temp table from within a stored procedure or UDF. This is a basic construct, so feel free to revise as needed.
For example:
CREATE PROCEDURE GetMinSpeed() AS
BEGIN
CREATE TABLE #speed (Driver NVARCHAR(10), SPEED INT);
'
' Insert any number of data you need to sort and pull from
'
INSERT INTO #speed (N'Petty', 165)
INSERT INTO #speed (N'Earnhardt', 172)
INSERT INTO #speed (N'Patrick', 174)
SELECT MIN(SPEED) FROM #speed
DROP TABLE #speed
END
Select MIN(T.V) FROM (Select 1 as V UNION Select 2 as V) T
SELECT (WHEN first > second THEN second ELSE first END) the_minimal FROM table