Select a column if other column is null - sql

I need to select a field called ProgramID from a table and if the ProgramID is NULL then I need to select the value in the InterimProgramID from the same table and alias it as ProgramID.
How can I make a conditional SELECT statement to do this?

You need the ISNULL function.
SELECT ISNULL(a, b)
b gets selected if a is null.
Also, you can use the WHEN/THEN select option, lookup in BOL. Essentially: its c switch/case block meets SQL.

select COALESCE ( ProgramID , InterimProgramID ) as 'ProgramID'

You can use either the ISNULL function or the COALESCE function. They both do pretty much the same thing, however ISNULL only takes two parameters and COALESCE takes multiple parameters (returning the first non-null it encounters). Both try the first param, then the second, (and COALESCE continues on)
DECLARE #IAMNULL VARCHAR
DECLARE #IAMNOTNULL VARCHAR
SET #IAMNOTNULL = 'NOT NULL'
SELECT ISNULL(#IAMNULL, #IAMNOTNULL)
--Output: 'NOT NULL'
DECLARE #IAMNULLALSO VARCHAR
SELECT COALESCE(#IAMNULL, #IAMNULLALSO, #IAMNOTNULL)
--Output: 'NOT NULL'

SELECT ProgramID
FROM a_table
WHERE ProgramID IS NOT NULL
UNION
SELECT InterimProgramID AS ProgramID
FROM a_table
WHERE ProgramID IS NULL;

Coalesce('zzz-' + ProgramID, InterimID) as programID will still ignore ProgramID even if you have a pretext value. It's a cool little function

There is also:
Select NVL(Column_A, Column_B) From 'schema'.'table_name'
The NVL( ) function is available in Oracle, and not in MySQL or SQL Server. This function is used to replace NULL value with another value. It is similar to the IFNULL Function in MySQL and the ISNULL Function in SQL Server.
https://www.1keydata.com/sql/sql-nvl.html

You can also use IFNULL function
select IFNULL(ProgramId,interimId) as ProgramId

Related

T-SQL get substring

I am looking to get an order number from a column named KEY_Ref, this ref column have various contents, but some rows look like this
LINE_NO=15^ORDER_NO=176572^RELEASE_NO=1^
Now I am interested in getting the value for ORDER_NO (176572 in this case)
How would I (In SQL Server) go about getting this (Or other) value from the main string
The logic is always
key1=value1^key2=value2^key3=value3^
You can use string_split():
select t.*, s.orderno
from t outer apply
(select stuff(s.value, 1, 9, '') as orderno
from string_split(t.key_ref, '^') s
where s.value like 'ORDER_NO=%'
) s;
Here is a db<>fiddle.
this is going to be a bit lengthy answer however if your SQL server version doesn't support string_split function you may use this.
declare #str varchar(100) = 'LINE_NO=15^ORDER_NO=176572^RELEASE_NO=1^'
declare #substr1 varchar(50) = substring(#str,charindex('^',#str)+1,len(#str))
declare #substr2 varchar(50) = substring(#substr1,charindex('=',#substr1)+1,charindex('^',#substr1)-charindex('=',#substr1)-1)
select #substr2 as 'order number'
the final variable will produce the desired value and you must merge the above queries to a single query that can fetch the value from the table in a single select statement.
this will work only if the pattern doesn't deviate from the one you've mentioned.

SQL HASHBYTES function returns weird output when used in CASE WHEN/IIF

I have written a stored procedure that hashes the value of a certain column. I need to use this HASHBYTES function in a CASE WHEN or IIF statement, like this:
DECLARE #Hash varchar(255) = 'testvalue'
SELECT IIF(1=1, HASHBYTES('SHA1',#Hash), #Hash)
SELECT CASE WHEN 1=1 THEN HASHBYTES('SHA1',#Hash) END AS Hashcolumn
I can't get my head around why I get different outputs from above queries? it seems that whenever I add an ELSE in the CASE WHEN / IIF statement, it returns a string of weird characters (like ü<þ+OUL'RDOk{­\Ìø in above example).
Can anyone tell me why this is happening? I need to use the CASE WHEN or IIF.
Thanks guys
IIF returns the data type with the highest precedence from the types in true_value and false_value. In this case, it's #Hash1 which is varchar(255) so your result is getting cast to varchar(255). See below.
DECLARE #Hash varchar(255) = 'testvalue'
SELECT cast(HASHBYTES('SHA1',#Hash) as varchar(255))
Similarly, CASE works the same way. However, if you don't add an ELSE or another WHEN that would conflict with the data type, it will work. This is because an ELSE NULL is implied. i.e.
SELECT CASE WHEN 1=1 THEN HASHBYTES('SHA1',#Hash) END
However, if you add another check, then precedence kicks in, and it will be converted.
SELECT CASE WHEN 1=1 THEN HASHBYTES('SHA1',#Hash) WHEN 1=2 THEN #Hash END AS Hashcolumn
SELECT CASE WHEN 1=1 THEN HASHBYTES('SHA1',#Hash) ELSE #Hash END AS Hashcolumn
The output of a select query is a virtual table. In a relational db a column of a table is constrained to single data type.. so here what happens is implicit conversion is being done by the server engine inorder to render a sigle type and hence weird characters are returned.
The nature of conversion is as #scsimon says it follows highest precedence order.
The following query should help.
DECLARE #Hash varchar(255) = 'testvalue'
SELECT IIF(1=1, CONVERT(VARCHAR(255),HASHBYTES('SHA1',#Hash),2), #Hash)
SELECT CASE WHEN 1=2 THEN CONVERT(VARCHAR(255),HASHBYTES('SHA1',#Hash),2)
ELSE #Hash END AS Hashcolumn

Building Dynamic Query Using Case in Where Clause

I have a stored procedure and I want implement the following query using Case Statement , but I am not sure how to do it .
pseudocode of what I want is provided here :
declare #PI_X decimal(18);
declare #PI_y decimal (18);
SELECT F1, F2,F3
FROM TABLE T
WHERE
CASE
WHEN #PI_X IS NULL THEN #PI_Y = T.Y
WHEN #PI_Y IS NULL THEN #PI_X = T.X
It seems that using case statement for conditions is not true and its for values.
NOTE:
I want to run this query in DB2 and SQL server , but really Data Base vendor is not important for me ,using sql dynamic query and (OR) in where clause has a performance hit . and I don't want it. I really like to know how it's possible to achieve such a logic using case in where clause.
Could you please help me to handle this problem . Any help and suggestions would be so appreciated .
The result of a CASE expression is a value, not an expression. You can't use a CASE expression to decide which code will run. You can only use it to choose what value will be used with your code.
In this case, you can accomplish your goal like this:
declare #PI_X decimal(18);
declare #PI_y decimal (18);
SELECT F1, F2,F3
FROM TABLE T
WHERE 1 =
CASE
WHEN #PI_X IS NULL AND #PI_Y = T.Y THEN 1
WHEN #PI_X IS NOT NULL AND #PI_Y IS NULL AND #PI_X = T.X THEN 1
ELSE 0 END
You could also try it like this:
declare #PI_X decimal(18);
declare #PI_y decimal (18);
SELECT F1, F2,F3
FROM TABLE T
WHERE coalesce(#PI_X, T.X) = T.X AND coalesce(#PI_y, T.Y) = T.Y
Though this second option might produce unexpected results if #PI_y might be something other than NULL when #PI_x has a value. If you can guarantee one or the other of the two variables will have a value, but never both, then you could also simplify the first option to remove the extra #PI_X IS NOT NULL AND part of the expression.
I'm not sure why your question is tagged with both SQL Server AND DB2... But I'll assume SQL Server...
declare #PI_X decimal(18);
declare #PI_y decimal (18);
SELECT
T.F1,
T.F2,
T.F3
FROM
TABLE T
WHERE
(#PI_X = T.X OR #PI_X IS NULL)
AND ((#PI_y = T.Y OR #PI_y IS NULL)
OPTION (RECOMPILE); -- Prevent's the forced scan operation cause by the use of "optional" parameters.
You can try out putting the if condition which will be readable however increasing the lines of code.
if(#PI_X IS NULL)
begin
select
....
where
T.Y=#PI_Y
end
else
begin
select
....
where
T.X = #PI_X
end
Instead of using an OR in the WHERE clause you could also build 2 separate queries and use IF...ELSE... to decide which one to use; something along the lines of what Coder1991 suggested. Or you could use a UNION ALL construction to avoid the IF and eliminate any branching.
SELECT F1, F2,F3
FROM TABLE T
WHERE #PI_X IS NULL
AND #PI_Y = T.Y
UNION ALL
SELECT F1, F2,F3
FROM TABLE T
WHERE #PI_Y IS NULL
AND #PI_X = T.X

XQuery Comparison Expressions in SQL Column

I would like to have a table that I can store XQuery Comparison Expressions in, so that I can evaluate them in a query.
I've been doing a bit of R&D into if it is possible, and I'm struggling.
If I put an XQuery expression in a column, then it seems to evaluate differently to if I put the XQuery expression directly into the query. For example, when I run the below query:
declare
#x xml = ''
create table #condition
(
condition nvarchar(255)
)
insert into #condition
values
('''1''=''1''')
select
condition,
#x.query('sql:column("condition")'),
#x.query('''1''=''1''')
from #condition
I would expect this to return:
'1'='1', true, true
However it actually returns:
'1'='1', '1'='1', true
Does anybody know how I can evaluate comparison expressions that are stored in a column?
The eventual plan is to be able to use this technique to filter down rows of a table based on XQuery conditions present. So ultimately I'd want to be able to do this in the where clause of a select statement.
I've put the above example into an sql fiddle encase it is useful.
Many thanks
Short answer: Unfortunately you can't.
sql:column("condition") will be evaluated to a suitable XML primitive data type based on the table column type. In this case the value from condition column will always be evaluated as XML string type instead of an XQuery statement, as you have figured out from running your sample query. And I can't see anyway of evaluating dynamic XQuery statement, unless you want to construct the entire query dynamically and execute it later on possibly using sp_executesql.
Try this query:
declare
#x xml = ''
create table #condition
(
condition nvarchar(255)
)
insert into #condition
values
('''1''=''1''')
select
condition,
case when col1 like col2 then 'True' else 'False' END col,
quer
from
(
select
condition,
PARSENAME(REPLACE(condition,'=','.'),2) col1,
PARSENAME(REPLACE(condition,'=','.'),1) col2 ,
#x.query('''1''=''1''') as quer
from #condition
)base

Comparing 2 variables in SQL stored procedure where 1 of them could be NULL [duplicate]

I must to check if two values, X and Y are different. If both are null, they must be considered as equal.
The unique way I found is:
select 1 as valueExists
where (#X is null and #Y is not null)
or (#Y is null and #X is not null)
or (#X <> #Y)
Is there a smart way to write this expression?
Thanks!
I think you could use COALESCE for that
WHERE coalesce(#X, '') <> coalesce(#Y, '')
What it does it returns an empty string if one of variables is null, so if two variables are null the two empty strings become equal.
I typically use a technique I picked up from here
SELECT 1 AS valuesDifferent
WHERE EXISTS (SELECT #X
EXCEPT
SELECT #Y)
WHERE EXISTS returns true if the sub query it contains returns a row. This will happen in this case if the two values are distinct. null is treated as a distinct value for the purposes of this operation.
You could try using NULLIF like this:
WHERE NULLIF(#X,#Y) IS NOT NULL OR NULLIF(#Y,#X) IS NOT NULL
You can use ISNULL
WHERE ISNULL(#X,'') <> ISNULL(#Y,'')