Syntax Errors With Case Statement in SQL - sql

If the When conditions are correct, then I want it to be labeled as 'Suspended for Audit....' if they are not correct, then have it be either blank or filled in by the t.fstrTaskSource + 'TYP' + t.fstrType statement (this part works already)
SELECT t.flngKey AS flngTaskKey,
t.fstrAccountType,
t.fstrTaskSource,
CASE t.fstrCategory
WHEN '' THEN ''
ELSE t.fstrTaskSource + '_CAT_' + t.fstrCategory
END AS fstrCategory,
CASE t.fstrType
WHEN '' THEN ''
WHEN (wd.fstrWorkType = 'SUSIN1' -- I am getting a syntax error here on the = sign --
AND wd.fstrOwner = ' '
AND wd.flngworkkey = wr.flngworkkey
AND wr.fstrAccountType <> '007'
AND wr.fblnOpen = 1
AND EXISTS
(SELECT 1
FROM tblIndicator i
WHERE i.fstrIndicator = 'EIWTCH'
AND i.flngVer = 0
AND i.flngAccountKey = wd.flngAccountKey)) -- I am also getting an error here on the ) sign --
THEN 'Suspended for Audit Indicator - EIC Watch For'
ELSE t.fstrTaskSource + '_TYP_' + t.fstrType
END AS fstrType

Your second Case Expression is a mix of Simple Case and Searched Case.
I.e.
CASE t.fstrType
WHEN '' THEN ''
WHEN (wd.fstrWorkType = 'SUSIN1'
Change it to a Searched Case expression as:
CASE WHEN t.fstrType = '' THEN ''
WHEN (wd.fstrWorkType = 'SUSIN1' ...
Two formats of Case Expression are:
--Simple CASE expression:
CASE input_expression
WHEN when_expression THEN result_expression [ ...n ]
[ ELSE else_result_expression ]
END
--Searched CASE expression:
CASE
WHEN Boolean_expression THEN result_expression [ ...n ]
[ ELSE else_result_expression ]
END

Your are trying to use the two syntax of CASE in the same time
the first:
case expression
when "val1" then ..
when "val2" then ..
end
the second:
case
when column = "val1" then ..
when column2 = "val2" then ..
end
So, use this in your second CASE:
CASE
WHEN t.fstrType = '' THEN ''
WHEN (wd.fstrWorkType = 'SUSIN1' ...

Related

Using prompts in Select Case statements

I want to use select case for my prompts. Condition is that when the prompt :4 = 'I' then prompt :5 equals all of its values, and I use the code below but i receive the following error.
Error in running query because of SQL Error, Code=936, Message=ORA-00936: missing expression (50,380)
2 = 2 AND (CASE :5
WHEN :4 = 'I' AND :5 = ' '
THEN :5 = '%'
END)
Anything wrong with my case statemnt?
There are two different syntaxes for CASE:
CASE value1
WHEN value2 THEN expression1
WHEN value2 THEN expression2
ELSE expression3
END
and:
CASE
WHEN boolean_expression THEN expression1
WHEN boolean_expression THEN expression2
ELSE expression3
END
Note: The first statement can be converted to the second as
CASE
WHEN value1 = value2 THEN expression1
WHEN value1 = value3 THEN expression2
ELSE expression3
END
You are mixing these two syntaxes and it is invalid SQL.
You appear to want:
:5 = CASE WHEN :4 = 'I' AND :5 = ' ' THEN '%' END
However, even that will not work as bind variables are set once and are not re-evaluated so your logic would be:
( ( :4 = 'I' AND :5 = ' ' ) AND :5 = '%' )
OR ( NOT ( :4 = 'I' AND :5 = ' ' ) AND :5 = NULL )
Since :5 cannot ever be both ' ' and '%' then that branch of the logic can never be true and anything (including NULL) is never equal to NULL so the second branch of the logic is also never true; therefore your expression will never match anything.
Just create an expression like this
decode(:4,'I',:5,SOMEVALUEORFIELD) = :5
This is your case expression:
(CASE :5 WHEN :4 = 'I' AND :5 = ' ' THEN :5 = '%'
END)
I cannot figure out what you really want. Both the CASE :5 and the :5 = '%' are improper. Perhaps:
(CASE WHEN :4 = 'I' AND :5 = ' ' THEN '%'
END) as :5
However, you don't normally use parameters for column aliases.

Display Column value according to need in sql

if i have a column in which ten digit values occurs like Column A = 11111000 so how to show this value in sql like (List,Add,Edit,Delete,Export) in sql.
there is a condition means if first position have 1 then it show List, If second Position have 1 it show Add, third position have 1 then Edit, fourth position have 1 then Delete, fifth position have 1 then Export.
If the value is a string, you can do:
select stuff( ((case when substring(a, 1, 1) = 1 then ',List' else '' end) +
(case when substring(a, 2, 1) = 1 then ',Add' else '' end) +
. . .
), 1, 1, '')
The logic is similar for bitwise operators:
select stuff( ((case when a & 2^9 then ',List' else '' end) +
(case when 2 & 2^8 then ',Add' else '' end) +
. . .
), 1, 1, '')
Maybe Substring function can help you to identify these values
select
id, ColumnA,
case when substring(ColumnA,1,1) = '1' then 'X' end as List,
case when substring(ColumnA,2,1) = '1' then 'X' end as [Add],
case when substring(ColumnA,3,1) = '1' then 'X' end as Edit,
case when substring(ColumnA,4,1) = '1' then 'X' end as [Delete],
case when substring(ColumnA,5,1) = '1' then 'X' end as [Export]
from Table1
I update the query according to comment
select
id, ColumnA,
stuff(
case when substring(ColumnA,1,1) = '1' then ',List' else '' end +
case when substring(ColumnA,2,1) = '1' then ',Add' else '' end +
case when substring(ColumnA,3,1) = '1' then ',Edit' else '' end +
case when substring(ColumnA,4,1) = '1' then ',Delete' else '' end +
case when substring(ColumnA,5,1) = '1' then ',Export' else '' end
,1,1,''
)
from Table1

SQL working strange

When I execute this SQL code:
select id, opis, vidrabota, tipprov, hitnost, valuta, drzava, zbirnaprov, tip_zbirprov, kanal
from dev_1450autoebanktip
where opis is null or Opis like case when isnull('','') = '' then Opis else '%' + '' + '%' end
and VidRabota = case when isnull('','') = '' then VidRabota else '' end
and TipProv = case when isnull(0,0) = 0 then TipProv else 0 end
and Valuta = case when isnull('','') = '' then Valuta else '' end
and drzava is null or Drzava = case when isnull('','') = '' then Drzava else '' end
I get this set of results:
But when I add one more condition (last row):
select id, opis, vidrabota, tipprov, hitnost, valuta, drzava, zbirnaprov, tip_zbirprov, kanal
from dev_1450autoebanktip
where opis is null or Opis like case when isnull('','') = '' then Opis else '%' + '' + '%' end
and VidRabota = case when isnull('','') = '' then VidRabota else '' end
and TipProv = case when isnull(0,0) = 0 then TipProv else 0 end
and Valuta = case when isnull('','') = '' then Valuta else '' end
and drzava is null or Drzava = case when isnull('','') = '' then Drzava else '' end
and KANAL = case when isnull(0,0) = 0 then KANAL else 0 end
I am losing one row in the result. What is causing this change?
Kanal is NULL in the last row.
and KANAL = case when isnull(0,0) = 0 then KANAL else 0 end
boils down to
and KANAL = KANAL
But this is not true for NULL, because NULL is the unknown value. When comparing null with null the result is neither true nor false, but unknown. Thus the added criteria dismisses the last record.
There is one thing I'd like to add: Use parentheses when mixing AND and OR. For instance
a = b or a = c and d = e
means
a = b or (a = c and d = e)
because AND has precedence over OR and you may want the expression to mean
(a = b or a = c) and d = e
Use parentheses in order to avoid any mistakes.

Multiple case statement not working as expected in Postgres

This is the query:
SELECT DISTINCT
completed_phases,
CAST(completed_phases::bit(8) AS VARCHAR),
CASE WHEN STRPOS(CAST(completed_phases::bit(8) AS VARCHAR),'1')=1 THEN 'FT' ELSE '' END ||
CASE WHEN STRPOS(CAST(completed_phases::bit(8) AS VARCHAR),'1')=2 THEN 'ED' ELSE '' END ||
CASE WHEN STRPOS(CAST(completed_phases::bit(8) AS VARCHAR),'1')=3 THEN 'MC' ELSE '' END ||
CASE WHEN STRPOS(CAST(completed_phases::bit(8) AS VARCHAR),'1')=4 THEN 'HC' ELSE '' END ||
CASE WHEN STRPOS(CAST(completed_phases::bit(8) AS VARCHAR),'1')=5 THEN 'UV' ELSE '' END ||
CASE WHEN STRPOS(CAST(completed_phases::bit(8) AS VARCHAR),'1')=6 THEN 'TT' ELSE '' END ||
CASE WHEN STRPOS(CAST(completed_phases::bit(8) AS VARCHAR),'1')=7 THEN 'RX' ELSE '' END ||
CASE WHEN STRPOS(CAST(completed_phases::bit(8) AS VARCHAR),'1')=8 THEN 'PI' ELSE '' END
FROM rx_sales_order
If completed_phase is 129, my output for final column should be FTPI. But it is only showing FT. Only the first case statement seems to work, even if all of them are distinct.
STRPOS() will always return the first occurance of the searched string. So all calls to strpos() will return 1 for the input value 129.
You can use substring() instead:
CASE WHEN substring(CAST(completed_phases::bit(8) AS VARCHAR),1,1)='1' THEN 'FT' ELSE '' END ||
CASE WHEN substring(CAST(completed_phases::bit(8) AS VARCHAR),2,1)='1' THEN 'ED' ELSE '' END ||
CASE WHEN substring(CAST(completed_phases::bit(8) AS VARCHAR),3,1)='1' THEN 'MC' ELSE '' END ||
CASE WHEN substring(CAST(completed_phases::bit(8) AS VARCHAR),4,1)='1' THEN 'HC' ELSE '' END ||
CASE WHEN substring(CAST(completed_phases::bit(8) AS VARCHAR),5,1)='1' THEN 'UV' ELSE '' END ||
CASE WHEN substring(CAST(completed_phases::bit(8) AS VARCHAR),6,1)='1' THEN 'TT' ELSE '' END ||
CASE WHEN substring(CAST(completed_phases::bit(8) AS VARCHAR),7,1)='1' THEN 'RX' ELSE '' END ||
CASE WHEN substring(CAST(completed_phases::bit(8) AS VARCHAR),8,1)='1' THEN 'PI' ELSE '' END
Another option would be to use get_bit() to test each bit individually:
case when get_bit(completed_phases::bit(8), 0) = 1 then 'FT' else '' END||
case when get_bit(completed_phases::bit(8), 1) = 1 then 'ED' else '' END||
case when get_bit(completed_phases::bit(8), 2) = 1 then 'MC' else '' END||
case when get_bit(completed_phases::bit(8), 3) = 1 then 'HC' else '' END||
case when get_bit(completed_phases::bit(8), 4) = 1 then 'UV' else '' END||
case when get_bit(completed_phases::bit(8), 5) = 1 then 'TT' else '' END||
case when get_bit(completed_phases::bit(8), 6) = 1 then 'RX' else '' END||
case when get_bit(completed_phases::bit(8), 7) = 1 then 'PI' else '' END
A more flexible way of doing that is to turn the bits into rows and use an array as a lookup. Something like:
with lookup (codes) as (
values (array['FT','ED','MC','HC','UV','TT','RX','PI'])
)
SELECT completed_phases,
completed_phases::bit(8),
x.code
FROM rx_sales_order
join lateral (
select string_agg(codes[i],'') as code
from lookup, unnest(string_to_array(completed_phases::bit(8)::text, null)) with ordinality as t(b,i)
where b = '1'
) as x on true
The part regexp_split_to_table(completed_phases::bit(8)::text, '') with ordinality as t(b,i) will return the following for the value 129:
b | i
--+--
1 | 1
0 | 2
0 | 3
0 | 4
0 | 5
0 | 6
0 | 7
1 | 8
code[i] the uses the index to lookup the matching code and string_agg() then puts all selected codes together again into a single string. The condition where b = '1' only selects the bits that are set.
That solution will be substantially slower than the hardcoded case expression (because it increases the number of rows, just to reduce them again) - but it is more flexible and easier to maintain.
If you need that a lot, the best option would be to put the case expression into a function and use the function in your queries.
create or replace function get_codes(p_phases integer)
returns text
as
$$
select
case when get_bit(p_phases::bit(8), 0) = 1 then 'FT' else '' END||
case when get_bit(p_phases::bit(8), 1) = 1 then 'ED' else '' END||
case when get_bit(p_phases::bit(8), 2) = 1 then 'MC' else '' END||
case when get_bit(p_phases::bit(8), 3) = 1 then 'HC' else '' END||
case when get_bit(p_phases::bit(8), 4) = 1 then 'UV' else '' END||
case when get_bit(p_phases::bit(8), 5) = 1 then 'TT' else '' END||
case when get_bit(p_phases::bit(8), 6) = 1 then 'RX' else '' END||
case when get_bit(p_phases::bit(8), 7) = 1 then 'PI' else '' END
$$
language sql;
Then use:
SELECT DISTINCT
completed_phases,
get_codes(completed_phases) as codes
FROM rx_sales_order
As pointed out in the answer by a_horse_with_no_name, strpos will return the first occurrence of the searched string. At any rate, it's better to use get_bit instead of casting to VARCHAR to check if a bit is set. Also, instead of ||, you can use concat, which will handle nulls as blank strings. Your query could then be rewritten to:
SELECT DISTINCT
completed_phases,
CAST(completed_phases::bit(8) AS VARCHAR),
concat(CASE get_bit(completed_phases::bit(8), 0) WHEN 1 THEN 'FT' END,
CASE get_bit(completed_phases::bit(8), 1) WHEN 1 THEN 'ED' END,
CASE get_bit(completed_phases::bit(8), 2) WHEN 1 THEN 'MC' END,
CASE get_bit(completed_phases::bit(8), 3) WHEN 1 THEN 'HC' END,
CASE get_bit(completed_phases::bit(8), 4) WHEN 1 THEN 'UV' END,
CASE get_bit(completed_phases::bit(8), 5) WHEN 1 THEN 'TT' END,
CASE get_bit(completed_phases::bit(8), 6) WHEN 1 THEN 'RX' END,
CASE get_bit(completed_phases::bit(8), 7) WHEN 1 THEN 'PI' END)
FROM rx_sales_order;
On a side note, if you have the option to do so, I would recommend changing your database schema to store the phases as individual boolean columns instead of using a bit map. See Any disadvantages to bit flags in database columns? for a good discussion of why.

Using a Case statement to set a parameter based on another parameter

I'm trying to set an SQL variable based on the numerical value of a different SQL parameter passed into a stored procedure, but having trouble with the exact syntax of the Case statement
DECLARE #RangeText varchar(1)
SELECT CASE
WHEN (#SecondsOnSiteRange = 1)
THEN SET #RangeText = '=' END
WHEN (#SecondsOnSiteRange = 2)
THEN SET #RangeText = '>' END
WHEN (#SecondsOnSiteRange = 3)
THEN SET #RangeText = '<' END
ELSE NULL
END
I'm sure it will be something small like a missing keyword or something, but when I search Google all I seems to be able to find is setting a the same variable, not a second one.
Correct syntax:
Simple CASE expression:
CASE input_expression
WHEN when_expression THEN result_expression [ ...n ]
[ ELSE else_result_expression ]
END
Searched CASE expression:
CASE
WHEN Boolean_expression THEN result_expression [ ...n ]
[ ELSE else_result_expression ]
END
Code:
DECLARE #RangeText varchar(1)
SELECT #RangeText = CASE
WHEN (#SecondsOnSiteRange = 1) THEN '='
WHEN (#SecondsOnSiteRange = 2) THEN '>'
WHEN (#SecondsOnSiteRange = 3) THEN '<'
ELSE NULL
END
or:
SELECT #RangeText = CASE #SecondsOnSiteRange
WHEN 1 THEN '='
WHEN 2 THEN '>'
WHEN 3 THEN '<'
ELSE NULL
END
You should only use end at the end like this:
SELECT CASE
WHEN (#SecondsOnSiteRange = 1)
THEN SET #RangeText = '=' ELSE
WHEN (#SecondsOnSiteRange = 2)
THEN SET #RangeText = '>' ELSE
WHEN (#SecondsOnSiteRange = 3)
THEN SET #RangeText = '<' ELSE
ELSE NULL
END
I am extremely sorry the above is incorrect. I did overlook, below is how it should be done...
SELECT #RangeText =
CASE WHEN (#SecondsOnSiteRange = 1)
THEN '='
WHEN (#SecondsOnSiteRange = 2)
THEN '>'
WHEN (#SecondsOnSiteRange = 3)
THEN '<'
ELSE NULL
END