SQL server IF begin statement in where function - sql

I'm trying to create the following in a where statement.
where Registration_Date >=#StartDate and Registration_Date < dateadd(day,1,#EndDate)
and if #affiliateid is null begin Channel in (select Value from dbo.Split(',',#Channel)) end
else Affiliate_Id in (select Value from dbo.Split(',', #AffiliateId))
and Registration_Channel in (select Value from dbo.Split(',', #Channel))
So, I am trying to say that if #AffiliateId is null, use the #Channel input for all Affiliate ids, if not then use the specific #AffiliateId, irrespective of channels.
Is there any way I could make this work?

SELECT *
FROM mytable
WHERE DATE(registration_date) BETWEEN #startDate AND #endDate
AND EXISTS
(
SELECT NULL
FROM dbo.split(',', COALESCE(#affiliateId, #channel))
WHERE value = CASE WHEN #affiliateId IS NULL THEN channel ELSE affiliateId END
)
AND EXISTS
(
SELECT NULL
FROM dbo.split(',', #channel)
WHERE value = registration_channel
)
In SQL Server 2008, DATE(column) is a sargable expression.

Related

How to check UNIQUEIDENTIFIER value and replace with select string value if it exist

I am working on SQL Server 2012 script and I need to do logic like this;
if ans.value is UNIQUEIDENTIFIER /Guid then select value(string) from xtable where xtable.value = ans.value else ans.value (ans.value will be either string or empty)
This is far I have achieved..
SELECT
ans.Id,
calculatedVal = ISNULL(TRY_CONVERT(UNIQUEIDENTIFIER, ans.Value), 'select from xtable....') ?????
FROM [Answers] AS ans
so basically I need to perform sql select and assign string value to 'calculatedVal' if TRY_CONVERT(UNIQUEIDENTIFIER, ans.Value) IS NOT NULL... how can I do that
You could use CASE:
SELECT
ans.Id,
CASE WHEN TRY_CONVERT(UNIQUEIDENTIFIER, ans.Value) IS NOT NULL THEN
(select TOP 1 col_name from xtable WHERE ... ORDER BY ...)
ELSE ans.Value
END AS calculatedVal
FROM [Answers] AS ans;
Or using IIF
SELECT
ans.Id,
IIF(TRY_CONVERT(UNIQUEIDENTIFIER, ans.Value) IS NOT NULL,
(select TOP 1 col_name from xtable WHERE ... ORDER BY ...)
,ans.Value)AS calculatedVal
FROM [Answers] AS ans;

Case Statement Sql Multiple column check for dates

I have a stored procdure that uses case statement as follows: What I am trying to do is evaluate 2 columns in the testTable for dates. So the below case statement says that if stop_date is null or greater than current date then set is_active cloumn is Y else N
What I am trying to do is also evaluate another date column say another_stop_date and check if it is null or has a date greater then today and use same logic to update the is_active column
I am not sure if we can use multiple case statement logic to update a single column?
I have commented the code below where I am not getting the right results
Basically need to evaluate stop_dt and another_stop_date columns from testTable!
USE [Test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[p_test]
#Blank_Row CHAR(1) = 'N'
AS
BEGIN
SET NOCOUNT ON
DECLARE #TD DATETIME
SELECT #TD = GETDATE()
DECLARE #tempTable TABLE (
ID INT,
c_id INT,
desc varchar(40),
date datetime,
s_col TinyINT,
is_active char(1),
stuff VARCHAR(8))
INSERT INTO #tempTable
SELECT id, c_id, desc, max( date ), 1,
CASE WHEN (stop_dt IS NULL OR stop_dt > #TD) THEN 'Y'
--//Case When (another_stop_date is NULL or another Stop_date > #TD) THEN 'Y'<-----confused here
ELSE 'N' END,
stuff
FROM testTable
GROUP BY id, stop_dt, c_id, desc, stuff, another_stop_date
Select * from tempTable
You can combine clauses in a case statement with the usual logical operators, as well as having separate cases:
Case
When
(stop_dt is null or stop_dt > #td) and
(another_stop_date is null or another_stop_date > #td)
Then 'Y'
Else 'N'
End
Case statement operate close to if statements and can have multiple clauses.
Case when condition_1 > 1 then 'hi'
when condition_1 < 14 then 'no'
when condition_89 > 12 then 'why is this here'
else 1
end
Apply it to your statement:
CASE WHEN (stop_dt IS NULL OR stop_dt > #TD) THEN 'Y'
When (another_stop_date is NULL or another Stop_date > #TD) THEN 'Y'<-----confused here
ELSE 'N' END

SQL Create View and using it in Function

I have the following function and I need to take out the SELECT part and create a separate view.
CREATE FUNCTION dbo.dbf_get_penalty_points
( #pn_seq_party_id NUMERIC(18),
#pv_penalty_points_code CHAR(1) = 'Y') -- Use 'N' for total points, otherwise will return Current Penalty Points
RETURNS NUMERIC(18,0)
AS
BEGIN
DECLARE #n_penalty_points NUMERIC(18),
#d_latest_points_date DATETIME
SELECT #d_latest_points_date = dbo.dbf_trunc_date(DateAdd(mm, - Abs(Convert(NUMERIC(18,0),dbo.dbf_get_sys_param('CMS2', 'PP_MONTHS'))), GetDate()))
SELECT #n_penalty_points = IsNull(Sum(penalty_points_amount),0)
FROM dbo.ar_penalty_point WITH(NOLOCK)
WHERE seq_party_id = #pn_seq_party_id
AND 1 = CASE
WHEN #pv_penalty_points_code = 'N' THEN 1
WHEN #pv_penalty_points_code = 'Y' AND added_date >= #d_latest_points_date AND reset_date IS NULL THEN 1
ELSE 0
END
RETURN #n_penalty_points
END
GO
SET QUOTED_IDENTIFIER OFF
GO
GRANT EXECUTE ON dbo.dbf_get_penalty_points TO standard
GO
I have tried and got this,
SELECT SUM(CASE WHEN added_date >=dbo.dbf_trunc_date(DateAdd(mm, - Abs(Convert(NUMERIC(18,0),dbo.dbf_get_sys_param('CMS2', 'PP_MONTHS'))), GetDate()))
AND reset_date IS NULL THEN 1
ELSE 0) current_points,
IsNull(Sum(penalty_points_amount),0) total_points,
seq_party_id
FROM dbo.ar_penalty_point WITH(NOLOCK)
GROUP BY seq_party_id
Now I need to get rid of
dbo.dbf_trunc_date(DateAdd(mm, - Abs(Convert(NUMERIC(18,0),dbo.dbf_get_sys_param('CMS2', 'PP_MONTHS'))), GetDate()))
From the SELECT part of the query. I am struck is there a better way to write my view ?
EDIT
The objective is to create a view that returns total_points and current_points. For better understanding refer the CREATE part following
CREATE FUNCTION dbo.dbf_get_penalty_points
( #pn_seq_party_id NUMERIC(18),
#pv_penalty_points_code CHAR(1) = 'Y') -- Use 'N' for total points, otherwise will return Current Penalty Points
Refer to -- Use 'N' for total points, otherwise will return Current Penalty Points in the comments
This is what I came up with
SELECT SUM(CASE WHEN (t.added_date >= t.target_date
AND t.reset_date IS NULL) THEN 1
ELSE 0 END) current_points,
IsNull(Sum(t.penalty_points_amount),0) total_points,
t.seq_party_id
FROM (
SELECT dbo.dbf_trunc_date(DateAdd(mm, - Abs(Convert(NUMERIC(18,0),dbo.dbf_get_sys_param('CMS2', 'PP_MONTHS'))), GetDate())) as target_date,
u.reset_date, u.penalty_points_amount,u.seq_party_id,u.added_date FROM
dbo.ar_penalty_point as u ) as t GROUP BY t.seq_party_id

IF ELSE condition in SQL select

I want to do a if-else condition statement in SQL Server but am not sure how.
Inside the stored procedure I have the following parameters:
#MarketId nvarchar (10),
#RegionId nvarchar (10)
And the following statement:
select * from Interaction I
where
(#MarketId = 0 ) OR (I.MarketId = (SELECT Id FROM Market WHERE ExternalId = #MarketId))
What I want to do is to check the value of #MarketId
if #MarketId = 0
then I want the where condition for I.MarketId to get its Ids from elsewhere like
(SELECT ID FROM Market WHERE ExternalId = #RegionId)
otherwise, if its 1, then I just want to leave it as is and get the Id from #MarketId instead of #RegionId..
How should I go about this?
Thanks!
This should work:
SELECT *
FROM Interaction I
WHERE ( #MarketID = 0
AND EXISTS (SELECT 1 FROM Market
WHERE ExternalId = #RegionId AND Id = I.MarketID)
OR I.MarketID = #MarketID

Is there a Max function in SQL Server that takes two values like Math.Max in .NET?

I want to write a query like this:
SELECT o.OrderId, MAX(o.NegotiatedPrice, o.SuggestedPrice)
FROM Order o
But this isn't how the MAX function works, right? It is an aggregate function so it expects a single parameter and then returns the MAX of all rows.
Does anyone know how to do it my way?
If you're using SQL Server 2008 (or above), then this is the better solution:
SELECT o.OrderId,
(SELECT MAX(Price)
FROM (VALUES (o.NegotiatedPrice),(o.SuggestedPrice)) AS AllPrices(Price))
FROM Order o
All credit and votes should go to Sven's answer to a related question, "SQL MAX of multiple columns?"
I say it's the "best answer" because:
It doesn't require complicating your code with UNION's, PIVOT's,
UNPIVOT's, UDF's, and crazy-long CASE statments.
It isn't plagued with the problem of handling nulls, it handles them just fine.
It's easy to swap out the "MAX" with "MIN", "AVG", or "SUM". You can use any aggregate function to find the aggregate over many different columns.
You're not limited to the names I used (i.e. "AllPrices" and "Price"). You can pick your own names to make it easier to read and understand for the next guy.
You can find multiple aggregates using SQL Server 2008's derived_tables like so: SELECT MAX(a), MAX(b) FROM (VALUES (1, 2), (3, 4), (5, 6), (7, 8), (9, 10) ) AS MyTable(a, b)
Can be done in one line:
-- the following expression calculates ==> max(#val1, #val2)
SELECT 0.5 * ((#val1 + #val2) + ABS(#val1 - #val2))
Edit: If you're dealing with very large numbers you'll have to convert the value variables into bigint in order to avoid an integer overflow.
You'd need to make a User-Defined Function if you wanted to have syntax similar to your example, but could you do what you want to do, inline, fairly easily with a CASE statement, as the others have said.
The UDF could be something like this:
create function dbo.InlineMax(#val1 int, #val2 int)
returns int
as
begin
if #val1 > #val2
return #val1
return isnull(#val2,#val1)
end
... and you would call it like so ...
SELECT o.OrderId, dbo.InlineMax(o.NegotiatedPrice, o.SuggestedPrice)
FROM Order o
I don't think so. I wanted this the other day. The closest I got was:
SELECT
o.OrderId,
CASE WHEN o.NegotiatedPrice > o.SuggestedPrice THEN o.NegotiatedPrice
ELSE o.SuggestedPrice
END
FROM Order o
Why not try IIF function (requires SQL Server 2012 and later)
IIF(a>b, a, b)
That's it.
(Extra hint: be careful about either a or b is null, as in this case the result of a>b will be false. So b will be the return result if either is null) (Also by system design, column null is not a good practice)
DECLARE #MAX INT
#MAX = (SELECT MAX(VALUE)
FROM (SELECT 1 AS VALUE UNION
SELECT 2 AS VALUE) AS T1)
In SQL Server 2012 or higher, you can use a combination of IIF and ISNULL (or COALESCE) to get the maximum of 2 values.
Even when 1 of them is NULL.
IIF(col1 >= col2, col1, ISNULL(col2, col1))
Or if you want it to return 0 when both are NULL
IIF(col1 >= col2, col1, COALESCE(col2, col1, 0))
Example snippet:
-- use table variable for testing purposes
declare #Order table
(
OrderId int primary key identity(1,1),
NegotiatedPrice decimal(10,2),
SuggestedPrice decimal(10,2)
);
-- Sample data
insert into #Order (NegotiatedPrice, SuggestedPrice) values
(0, 1),
(2, 1),
(3, null),
(null, 4);
-- Query
SELECT
o.OrderId, o.NegotiatedPrice, o.SuggestedPrice,
IIF(o.NegotiatedPrice >= o.SuggestedPrice, o.NegotiatedPrice, ISNULL(o.SuggestedPrice, o.NegotiatedPrice)) AS MaxPrice
FROM #Order o
Result:
OrderId NegotiatedPrice SuggestedPrice MaxPrice
1 0,00 1,00 1,00
2 2,00 1,00 2,00
3 3,00 NULL 3,00
4 NULL 4,00 4,00
But if one needs the maximum of multiple columns?
Then I suggest a CROSS APPLY on an aggregation of the VALUES.
Example:
SELECT t.*
, ca.[Maximum]
, ca.[Minimum], ca.[Total], ca.[Average]
FROM SomeTable t
CROSS APPLY (
SELECT
MAX(v.col) AS [Maximum],
MIN(v.col) AS [Minimum],
SUM(v.col) AS [Total],
AVG(v.col) AS [Average]
FROM (VALUES (t.Col1), (t.Col2), (t.Col3), (t.Col4)) v(col)
) ca
This has the extra benefit that this can calculate other things at the same time.
Try this. It can handle more than 2 values
SELECT Max(v) FROM (VALUES (1), (2), (3)) AS value(v)
The other answers are good, but if you have to worry about having NULL values, you may want this variant:
SELECT o.OrderId,
CASE WHEN ISNULL(o.NegotiatedPrice, o.SuggestedPrice) > ISNULL(o.SuggestedPrice, o.NegotiatedPrice)
THEN ISNULL(o.NegotiatedPrice, o.SuggestedPrice)
ELSE ISNULL(o.SuggestedPrice, o.NegotiatedPrice)
END
FROM Order o
Sub Queries can access the columns from the Outer query so you can use this approach to use aggregates such as MAX across columns. (Probably more useful when there is a greater number of columns involved though)
;WITH [Order] AS
(
SELECT 1 AS OrderId, 100 AS NegotiatedPrice, 110 AS SuggestedPrice UNION ALL
SELECT 2 AS OrderId, 1000 AS NegotiatedPrice, 50 AS SuggestedPrice
)
SELECT
o.OrderId,
(SELECT MAX(price)FROM
(SELECT o.NegotiatedPrice AS price
UNION ALL SELECT o.SuggestedPrice) d)
AS MaxPrice
FROM [Order] o
YES, THERE IS.
T-SQL (SQL Server 2022 (16.x)) now supports GREATEST/LEAST functions:
MAX/MIN as NON-aggregate function
This is now live for Azure SQL Database and SQL Managed Instance. It will roll into the next version of SQL Server.
Logical Functions - GREATEST (Transact-SQL)
This function returns the maximum value from a list of one or more expressions.
GREATEST ( expression1 [ ,...expressionN ] )
So in this case:
SELECT o.OrderId, GREATEST(o.NegotiatedPrice, o.SuggestedPrice)
FROM [Order] o;
db<>fiddle demo
SELECT o.OrderId,
--MAX(o.NegotiatedPrice, o.SuggestedPrice)
(SELECT MAX(v) FROM (VALUES (o.NegotiatedPrice), (o.SuggestedPrice)) AS value(v)) as ChoosenPrice
FROM Order o
I would go with the solution provided by kcrumley
Just modify it slightly to handle NULLs
create function dbo.HigherArgumentOrNull(#val1 int, #val2 int)
returns int
as
begin
if #val1 >= #val2
return #val1
if #val1 < #val2
return #val2
return NULL
end
EDIT
Modified after comment from Mark. As he correctly pointed out in 3 valued logic x > NULL or x < NULL should always return NULL. In other words unknown result.
SQL Server 2012 introduced IIF:
SELECT
o.OrderId,
IIF( ISNULL( o.NegotiatedPrice, 0 ) > ISNULL( o.SuggestedPrice, 0 ),
o.NegotiatedPrice,
o.SuggestedPrice
)
FROM
Order o
Handling NULLs is recommended when using IIF, because a NULL on either side of your boolean_expression will cause IIF to return the false_value (as opposed to NULL).
I probably wouldn't do it this way, as it's less efficient than the already mentioned CASE constructs - unless, perhaps, you had covering indexes for both queries. Either way, it's a useful technique for similar problems:
SELECT OrderId, MAX(Price) as Price FROM (
SELECT o.OrderId, o.NegotiatedPrice as Price FROM Order o
UNION ALL
SELECT o.OrderId, o.SuggestedPrice as Price FROM Order o
) as A
GROUP BY OrderId
Oops, I just posted a dupe of this question...
The answer is, there is no built in function like Oracle's Greatest, but you can achieve a similar result for 2 columns with a UDF, note, the use of sql_variant is quite important here.
create table #t (a int, b int)
insert #t
select 1,2 union all
select 3,4 union all
select 5,2
-- option 1 - A case statement
select case when a > b then a else b end
from #t
-- option 2 - A union statement
select a from #t where a >= b
union all
select b from #t where b > a
-- option 3 - A udf
create function dbo.GREATEST
(
#a as sql_variant,
#b as sql_variant
)
returns sql_variant
begin
declare #max sql_variant
if #a is null or #b is null return null
if #b > #a return #b
return #a
end
select dbo.GREATEST(a,b)
from #t
kristof
Posted this answer:
create table #t (id int IDENTITY(1,1), a int, b int)
insert #t
select 1,2 union all
select 3,4 union all
select 5,2
select id, max(val)
from #t
unpivot (val for col in (a, b)) as unpvt
group by id
Its as simple as this:
CREATE FUNCTION InlineMax
(
#p1 sql_variant,
#p2 sql_variant
) RETURNS sql_variant
AS
BEGIN
RETURN CASE
WHEN #p1 IS NULL AND #p2 IS NOT NULL THEN #p2
WHEN #p2 IS NULL AND #p1 IS NOT NULL THEN #p1
WHEN #p1 > #p2 THEN #p1
ELSE #p2 END
END;
You can do something like this:
select case when o.NegotiatedPrice > o.SuggestedPrice
then o.NegotiatedPrice
else o.SuggestedPrice
end
SELECT o.OrderID
CASE WHEN o.NegotiatedPrice > o.SuggestedPrice THEN
o.NegotiatedPrice
ELSE
o.SuggestedPrice
END AS Price
For the answer above regarding large numbers, you could do the multiplication before the addition/subtraction. It's a bit bulkier but requires no cast. (I can't speak for speed but I assume it's still pretty quick)
SELECT 0.5 * ((#val1 + #val2) +
ABS(#val1 - #val2))
Changes to
SELECT #val1*0.5+#val2*0.5 +
ABS(#val1*0.5 - #val2*0.5)
at least an alternative if you want to avoid casting.
Here's a case example that should handle nulls and will work with older versions of MSSQL. This is based on the inline function in one one of the popular examples:
case
when a >= b then a
else isnull(b,a)
end
-- Simple way without "functions" or "IF" or "CASE"
-- Query to select maximum value
SELECT o.OrderId
,(SELECT MAX(v)
FROM (VALUES (o.NegotiatedPrice), (o.SuggestedPrice)) AS value(v)) AS MaxValue
FROM Order o;
CREATE FUNCTION [dbo].[fnMax] (#p1 INT, #p2 INT)
RETURNS INT
AS BEGIN
DECLARE #Result INT
SET #p2 = COALESCE(#p2, #p1)
SELECT
#Result = (
SELECT
CASE WHEN #p1 > #p2 THEN #p1
ELSE #p2
END
)
RETURN #Result
END
Here is #Scott Langham's answer with simple NULL handling:
SELECT
o.OrderId,
CASE WHEN (o.NegotiatedPrice > o.SuggestedPrice OR o.SuggestedPrice IS NULL)
THEN o.NegotiatedPrice
ELSE o.SuggestedPrice
END As MaxPrice
FROM Order o
Here is an IIF version with NULL handling (based on of Xin's answer):
IIF(a IS NULL OR b IS NULL, ISNULL(a,b), IIF(a > b, a, b))
The logic is as follows, if either of the values is NULL, return the one that isn't NULL (if both are NULL, a NULL is returned). Otherwise return the greater one.
Same can be done for MIN.
IIF(a IS NULL OR b IS NULL, ISNULL(a,b), IIF(a < b, a, b))
select OrderId, (
select max([Price]) from (
select NegotiatedPrice [Price]
union all
select SuggestedPrice
) p
) from [Order]
In its simplest form...
CREATE FUNCTION fnGreatestInt (#Int1 int, #Int2 int )
RETURNS int
AS
BEGIN
IF #Int1 >= ISNULL(#Int2,#Int1)
RETURN #Int1
ELSE
RETURN #Int2
RETURN NULL --Never Hit
END
For SQL Server 2012:
SELECT
o.OrderId,
IIF( o.NegotiatedPrice >= o.SuggestedPrice,
o.NegotiatedPrice,
ISNULL(o.SuggestedPrice, o.NegiatedPrice)
)
FROM
Order o
Expanding on Xin's answer and assuming the comparison value type is INT, this approach works too:
SELECT IIF(ISNULL(#A, -2147483648) > ISNULL(#B, -2147483648), #A, #B)
This is a full test with example values:
DECLARE #A AS INT
DECLARE #B AS INT
SELECT #A = 2, #B = 1
SELECT IIF(ISNULL(#A, -2147483648) > ISNULL(#B, -2147483648), #A, #B)
-- 2
SELECT #A = 2, #B = 3
SELECT IIF(ISNULL(#A, -2147483648) > ISNULL(#B, -2147483648), #A, #B)
-- 3
SELECT #A = 2, #B = NULL
SELECT IIF(ISNULL(#A, -2147483648) > ISNULL(#B, -2147483648), #A, #B)
-- 2
SELECT #A = NULL, #B = 1
SELECT IIF(ISNULL(#A, -2147483648) > ISNULL(#B, -2147483648), #A, #B)
-- 1
In MemSQL do the following:
-- DROP FUNCTION IF EXISTS InlineMax;
DELIMITER //
CREATE FUNCTION InlineMax(val1 INT, val2 INT) RETURNS INT AS
DECLARE
val3 INT = 0;
BEGIN
IF val1 > val2 THEN
RETURN val1;
ELSE
RETURN val2;
END IF;
END //
DELIMITER ;
SELECT InlineMax(1,2) as test;