Oracle CASE in WHERE clause - oracle

Can someone help me with the below query in oracle?
The logic is that if the person has a friendlyname , use that for match with the 'search' criterion. Else, try to match with the realname column.
select * from people where
case when customer_friendlyname is null then realname like '%abcd%'
else
case when customer_friendlyname is not null then customer_friendlyname like '%abcd%'
end
end
Appreciated if someone could take a look.. Thank you!

In Oracle, Boolean expressions can't be treated like other types of expressions; for example, CASE expressions can't evaluate to them. So you need to rewrite this.
In this case, since you have the same LIKE '%abcd%' predicate in both branches, you could just factor it out:
WHERE ( CASE WHEN customer_friendlyname IS NULL
THEN realname
ELSE customer_friendlyname
END
) LIKE '%abcd%'
but it's simpler to make use of the built-in NVL function, and write:
WHERE NVL(customer_friendlyname, realname) LIKE '%abcd%'

SELECT *
FROM people
WHERE (customer_friendlyname LIKE '%abc%')
OR (customer_friendlyname is null and realname LIKE '%abc%')
You actually don't need the case here, this or clause will try the friendly name first it it was null it won't match, then it will try to match using the real name

You also can write it this way:
select * from people where
case
when customer_friendlyname is null and realname like '%abcd%'
then 1
when customer_friendlyname is not null and customer_friendlyname like '%abcd%'
then 1
else 0
end = 1
But it is more convenient in the case when you have more expressions.

Related

Difference in a one line block code between === and match?

I have the following code example to check whether some elements in an array match or not the given regular expression:
["SELECT column1, column2 FROM table1, table2 WHERE column2='value';",
"SELECT * FROM Customers WHERE Last_Name='Smith';",
"SELECT * FROM Friends"].none? { |sql| /WHERE/i.match?(sql) }
# false
As you can see, I'm using match? just to see if both the receiver and the method parameter match. I'm not interested on the pros of using match as it's stated on the docs:
Returns a true or false indicates whether the regexp is matched or not without updating $~ and other related variables. If the second parameter is present, it specifies the position in the string to begin the search.
So, I could easily use === for that:
["SELECT column1, column2 FROM table1, table2 WHERE column2='value';",
"SELECT * FROM Customers WHERE Last_Name='Smith';",
"SELECT * FROM Friends"].none? { |sql| /WHERE/ === sql }
# false
Which returns the very same. Maybe isn't so common to use case equality for this kind of things, but that allows me to pass the regular expression as the none? parameter, and avoid opening the block, as I'm using Ruby 2.5+:
array.none?(/WHERE/) # false
And works pretty much the same (also the same for every enumerable predicate method):
array.any? { |sql| /WHERE/i.match?(sql) } # true
array.any? { |sql| /WHERE/ === sql } # true
array.any?(/WHERE/) # true
So, my question is; would it be the same for me, considering these cases to use === to check every string instance in the arrays match with the given regular expression? If so, I could replace them all to just pass the regular expression as the method (none?, any?) parameter.
The reason for Regexp#=== existing is primarily for use in case statements, like:
case (str)
when /WHERE/i
# ...
end
As internally that calls the === to check for matches. This is why you can do a lot of really wild things like:
case (str)
when String
when 0..20
when 'example'
when /text/
end
Among other things, all by virtue of the === comparison.
It's worth noting it's not intended to be used as you have. match? communicates quite clearly your intent, but === may be confusing as it looks a lot like == which indicates "comparison", but this is not any ordinary comparison.
The good news is Ruby allows using a regular expression directly with any? as well as an alternative like:
[
"SELECT column1, column2 FROM table1, table2 WHERE column2='value';",
"SELECT * FROM Customers WHERE Last_Name='Smith';",
"SELECT * FROM Friends"
].grep(/WHERE/i).any?
Where the grep method can take either a string or a regular expression.
The grep method is great for filtering, but if you just want to know if any of them match it's not as efficient as any?, so I'd use that instead.

Oracle/ PLSQL condition like 'string' || '%'

Why this
SELECT * FROM STUDENT
WHERE FULLNAME LIKE 'Nguyen' || '%'
as the same
SELECT * FROM STUDENT
WHERE FULLNAME LIKE 'Nguyen%'
How does the first one work?
|| is concatenation operator. Oracle will first perform concatenation and then will use LIKE to match the pattern. Hence operationally it will be same as the second one.
However you should use the second one as it will be more efficient in performance and easy to read.
First one has extra overhead to append two strings before using LIKE to match the pattern.
the first one catenate 'Nguyen' and '%' through the pipes '||' in first place.
Because you don't have any space like 'Nguyen ' or ' %', it's the same as 'Nguyen%'.
There is no difference between these two:
Here the double pipe(||) is just a concatenation of expression.
Before db evaluate against like parameter, it concatenates
Hence both of those are same.
Both are same, as || operator concats 'Nguyen' and '%', it will be more helpful if you want to concat parameterize variable like below
SELECT * FROM STUDENT
WHERE FULLNAME LIKE :name || '%'

Replace NULL using a function

Is there any function to replace NULL or empty space with special character in hive? when I execute the below statement it returns a semantic exception stating trim works only on string/nvarchar
CASE
WHEN TRIM(q.address) = '' OR q.address IS NULL THEN '?'
ELSE q.address END as address
Please help.
Use LENGTH() to check the length of the column value. It returns > 0, if there is some value else return 0 for empty or NULL value.
Also frame the column value in CASE WHEN ... END block
The final query may look like:
SELECT CASE WHEN LENGTH(address) > 0 THEN address ELSE '?' END AS address
FROM table_name;
Please refer Replace the empty or NULL value with specific value in HIVE query result
Hope this help you!!!
In order to replace nulls you can use Coalesce
Coalesce( q.address, '?')
But it seems your field adress is not of the proper type to use trim, can you show us the type of that field?

Decoding with SUBSTRING and INSTRING?

I have a table which has city column having few records with state values as well-separated by comma.
There are other records without, as well. I want to take the state values for those present into a separate field called state.
How to do that? I tried the code below and it is saying "missing right parenthesis":
SELECT DECODE(ORA_CITY,
INSTR(ORA_CITY,',') > 0,
SUBSTR(ORA_CITY, INSTR(ORA_CITY, ','), LENGTH(ORA_CITY) ) ,
NULL) AS STATE
from ADDRESS
I don't know if you still need it but use CASE:
SELECT CASE
WHEN INSTR(ORA_CITY, '5') > 0 THEN
SUBSTR(ORA_CITY, INSTR(ORA_CITY, '5'), LENGTH(ORA_CITY))
ELSE
NULL
END STATE
FROM ADDRESS
Clearly you have not understood decode syntax.
Try the following:
SELECT DECODE(INSTR(ORA_CITY,','),
0,
NULL,
SUBSTR(ORA_CITY, INSTR(ORA_CITY, ','), LENGTH(ORA_CITY) )) AS STATE
FROM ADDRESS
The correct syntax is:
DECODE( expression , search , result [, search , result]... [,
default] ), where
expression is the value to compare.
search is the value that is compared against expression.
result is the value returned, if expression is equal to search.
default is optional. If no matches are found, the DECODE function will
return default. If default is omitted, then the DECODE function will
return null (if no matches are found).
Examples here and here
SELECT REGEX_REPLACE(ORA_CITY, '.*, *', '') AS STATE
FROM ADDRESS
WHERE ORA_CITY LIKE '%,%'
This uses regular expression to replace all upto the comma, and then maybe spaces with nothing. A WHERE included.

Whats the XPath equivalent to SQL In query?

I would like to know whats the XPath equivalent to SQL In query. Basically in sql i can do this:
select * from tbl1 where Id in (1,2,3,4)
so i want something similar in XPath/Xsl:
i.e.
//*[#id= IN('51417','1121','111')]
Please advice
(In XPath 2,) the = operator always works like in.
I.e. you can use
//*[#id = ('51417','1121','111')]
A solution is to write out the options as separate conditions:
//*[(#id = '51417') or (#id = '1121') or (#id = '111')]
Another, slightly less verbose solution that looks a bit like a hack, though, would be to use the contains function:
//*[contains('-51417-1121-111-', concat('-', #id, '-'))]
Literally, this means you're checking whether the value of the id attribute (preceeded and succeeded by a delimiter character) is a substring of -51417-1121-111-. Note that I am using a hyphen (-) as a delimiter of the allowable values; you can replace that with any character that will not appear in the id attribute.

Resources