Using IF in SELECT without referring to any column - sql

I've tried to follow this answer (to a different problem that what I have). However, I'm getting the error telling me that the syntax is incorrect near IF.
select if(1 < 2, 3, 4) as Reply
from Unit
The above is the exact syntax I'm using (the table Unit exists but has nothing to do with the values, of course. Sometimes I just wish to be able to manipulate some columns for better visibility when I play in SQL Studio.
Please note that I'm not asking about how to coalesce nor how to handle null values. If it appears like if I am, then either you've misunderstood the question or I haven't been clear with my explanation. Sorry about that in advance.

You are looking for the case clause:
select
case when 1 < 2
then 3
else 4 end as Reply
from Unit
Or if you only wish to see the result once (as opposed to for each row in the table):
select
case when 1 < 2 then 3 else 4 end as Reply

I believe this is the syntax you are looking for, it works from sqlserver 2012:
SELECT IIF( 1 < 2, 3, 4)
The syntax is:
IIF ( boolean_expression, true_value, false_value )

Related

SUBSTRING() function behaving differently in SELECT and WHERE clause? [duplicate]

This question already has an answer here:
Why is it that a change in query plan suddenly seems to break a query
(1 answer)
Closed 4 months ago.
This post was edited and submitted for review 4 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I have a table with the following column:
server
SLQ-ABCD-001
SLQ-ABCA-002
SLP-DBMSA-003
SLD-ABC-004
SLS-123456-005
I would like to be able to filter the rows based on a substring of this column, specifically, the string between those hyphens; there will always be three characters before the first hyphen and three characters after the second hyphen.
Here's what I have tried:
AND substring(server, 5, (len(server)-8)) in ('ABC', 'DBMSA')
AND substring(server, charindex('-', server)+1,(charindex('-',server, charindex('-', server)+1)-(charindex('-', server)+1))) in ('ABC', 'DBMSA')
Both of these work perfectly fine (expected substrings obtained) when used in the SELECT clause but give the error below
Invalid length parameter passed to the LEFT or SUBSTRING function.
I am not able to use the more simpler way, AND server like '%ABC%' as I have more than one combination of characters I'm looking for and also, because that comma separated list will be dynamically parsed in that query for this use case.
Is there any way this type of filter can be achieved in SQL Server?
EDIT
After #DaleK helped me realize that the issue might be I might have some bad data (server names with length < 8) and that I might have missed them when I tested the expression in the SELECT clause since I might have some other filters in my WHERE clause, here's how I had managed to get around that
SELECT *
from
(SELECT *
from my_original_table
where
--all my other filters that helped me eliminate the bad data
) my_filtered_table
where substring(server, 5, (len(server)-8)) in ('ABC', 'DBMSA');
As for the "question being duplicate" part, I think the error in that question is encountered in SELECT statement where as in my case, the expression worked fine in the SELECT statement and only errored when used in the WHERE clause.
For solution, the one provided by #Isolated seems to work perfectly fine!
One simpler approach you can try is the (often misused) parsename function:
Example being
with sampledata as (
select * from (
values('SLQ-ABCD-001'),('SLQ-ABCA-002'),('SLP-DBMSA-003'),('SLD-ABC-004'),('SLS-123456-005')
)x([server])
)
select [server]
from sampledata
cross apply(values(Replace([server], '-','.')))v(v)
where ParseName(v,2) in ('ABC', 'DBMSA');
No need for substring. You could nest left and right with len such as this:
with my_data as (
select 'SLQ-ABCD-001' as server union all
select 'SLQ-ABCA-002' union all
select 'SLP-DBMSA-003' union all
select 'SLD-ABC-004' union all
select 'SLS-123456-005'
)
select server
from my_data
where left(right(server, len(server) - 4), len(right(server, len(server) - 4))- 4) in ('ABC', 'DBMSA')
server
SLP-DBMSA-003
SLD-ABC-004
And left(right(server, len(server) - 4), len(right(server, len(server) - 4))- 4) works fine in the select clause too.

Strange issue combining IF and CASE in TSQL query

Here is an issue that seems like it should be a simple solve but I have been working on it some time and cannot figure out why I cannot seem to combine CASE in one area of the query and IF in another.
Does anyone see what is going on here? I have an old data set that needs to be converted to work with new tables. The data is pulled from WDDX and put in a temp table. That's all working properly.
Here is where I am running into trouble. I need to extract a value to a new column called DetailValue when XXXX appears, and in such cases, the value appearing after XXXX is a number that belongs to DetailValue, then it is followed by _, and in such case, the number appearing after _ belongs in RiskValue.. Also, when ZZZZ appears, the following character belongs in DetailValue and it is always the last character.
When it's simply CASE, everything works fine, but when I add IF to grab a value, it tells me:
"Incorrect syntax near the keyword 'IF'. Msg 156, Level 15, State 1, Procedure OldSysDataConv Incorrect syntax near the keyword 'THEN'.
Code is:
SELECT VarName,
CASE
WHEN (CHARINDEX('XXXX', VarName) > 0 and SUBSTRING(VarName, CHARINDEX('XXXX', VarName), len(VarName)) like '%XXXX%') or SUBSTRING(VarName, CHARINDEX('ZZZZ', VarName), len(VarName)) like '%ZZZZ%' then
left(replace(left(replace(VarName, 'XXXX', ''), len(VarName)-4), 'ZZZZ', ''), (len(VarName)-5))
else
null
END as DetailName,
IF CHARINDEX('ZZZZ', VarName) > 0 THEN
right(VarName, 1)
END
as DetailValue,
There is no such thing as IF ... THEN ... END expression in pure SQL. This is a procedural statement that is used in stored procedure.
You want either IIF(), which is T-SQL specific:
IIF(CHARINDEX('ZZZZ', VarName) > 0, right(VarName, 1), null) as DetailValue
Or the more standard CASE :
CASE WHEN CHARINDEX('ZZZZ', VarName) > 0 THEN right(VarName, 1) END as DetailValue
I solved my own problem by simplifying my CASE statement. Some basic logic had simply slipped by me during a long day. ;)
Answer:
CASE
WHEN CHARINDEX('XXXX', VarName) > 0 AND CHARINDEX('ZZZZ', VarName) <> 0 THEN
substring(VarName, (CHARINDEX('_', VarName)-1), len(VarName))
ELSE
right(VarName, 1)
END
as DetailValue,

Postgresql - CASE/WHEN with wrong return

I tried to use CASE/WHEN inside Postgresql to check two colums, but the results are odd.
As it's shown in the image below, all the lines where "gain_value" is 8 AND "patrimony_value" have a higher value return a wrong result.
This is my statement:
select stop_value, gain_value, patrimony_value,
case
when patrimony_value >= gain_value then 1
else 2
end
from copy.copy_stop_gain csg
Since it's a pretty straightforwad "if/else", i'm really not sure what i could be doing wrong.
Can anyone show me where is my mistake?
Try casting string values to numbers (or perhaps change column type in schema)...
select stop_value, gain_value, patrimony_value,
case
when patrimony_value::INTEGER >= gain_value::INTEGER then 1
else 2
end
from copy.copy_stop_gain csg

Hive - SELECT inside WHEN clause of CASE function gives an error

I am trying to write a query in Hive with a Case statement in which the condition depends on one of the values in the current row (whether or not it is equal to its predecessor). I want to evaluate it on the fly, this way, therefore requiring a nested query, not by making it another column first and comparing 2 columns. (I was able to do the latter, but that's really second-best). Does anyone know how to make this work?
Thanks.
My query:
SELECT * ,
CASE
WHEN
(SELECT lag(field_with_duplicates,1) over (order by field_with_duplicates) FROM my_table b
WHERE b.id=a.id) = a.field_with_duplicates
THEN “Duplicate”
ELSE “”
END as Duplicate_Indicator
FROM my_table a
Error:
java.sql.SQLException: org.apache.spark.sql.AnalysisException: cannot recognize input near 'SELECT' 'lag' '(' in expression specification; line 4 pos 9
Notes:
The reason I needed the complicated 'lag' function is that the unique Id's in the table are not consecutive, but I don't think that's where it's at: I tested by substituting another simpler inner query and got the same error message.
Speaking of 'duplicates', I did search on this issue before posting, but the only SELECT's inside CASE's I found were in the THEN statement, and if that works the same, it suggests mine should work too.
You do not need the subquery inside CASE:
SELECT a.* ,
CASE
WHEN prev_field_with_duplicates = field_with_duplicates
THEN “Duplicate”
ELSE “”
END as Duplicate_Indicator
FROM (select a.*,
lag(field_with_duplicates,1) over (order by field_with_duplicates) as prev_field_with_duplicates
from my_table a
)a
or even you can use lag() inside CASE instead without subquery at all (I'm not sure if it will work in all Hive versions ):
CASE
WHEN lag(field_with_duplicates,1) over (order by field_with_duplicates) = field_with_duplicates
THEN “Duplicate”
ELSE “”
END as Duplicate_Indicator
Thanks to #MatBailie for the answer in his comment. Don't I feel silly...
Resolved

Boolean expression as column value in transact sql

In most RDBMS:es, this work:
select (5 > 3)
and evaluates to true. It doesn't work in MS Transact SQL and the only workaround I've found is to write:
select case when 5 > 3 then 1 else 0 end
Which kind of sucks because it is much more verbose. Is there a better way to write the above kind of checks?
If the problem is arithmetic comparison:
select (5 - 3)
Then at the application level test for < or = or > 0.
You could write it as a scalar-valued function, but it will be very slow on large datasets.
If your program often requires such case constructs you could create your set of functions that will have user functions like Bool_IsGreater(left, right) that will return you your desired 0 or 1.
SQL Server doesn't support boolean value type anyway even for basic column use.
If you will need performance and those 5 and 3 values come naturally from some select query you might want to create a new column and set its value to 1 or 0 by trigger or something, which could help with performance.