How to get the last letter of a string? - oracle

How can I get the last letter of a string and check if it's vowel or consonant? I am using oracle 10g.
Here is what I came up with already:
SELECT last_name,
Substr(last_name, -1, 1) "Last letter",
Substr(last_name, 1, 1) "First letter",
CASE
WHEN Substr(last_name, -1, 1) IN ( 'a', 'e', 'i', 'o', 'u' ) THEN
'ends with a vowel'
WHEN Substr(last_name, -1, 1) IN ( 'b', 'c', 'd', 'f',
'g', 'h', 'j', 'k',
'l', 'm', 'n', 'p',
'q', 'r', 's', 't',
'v', 'w', 'x', 'y', 'z' ) THEN
'ends with a consonant'
END "Last Letter Description",
CASE
WHEN Substr(last_name, 1, 1) IN ( 'a', 'e', 'i', 'o', 'u' ) THEN
'starts with a consonant'
WHEN Substr(last_name, 1, 1) IN ( 'b', 'c', 'd', 'f',
'g', 'h', 'j', 'k',
'l', 'm', 'n', 'p',
'q', 'r', 's', 't',
'v', 'w', 'x', 'y', 'z' ) THEN
'starts with a consonant'
END "First Letter Description"
FROM employees
GROUP BY first_name,
last_name
Now when you execute this on oracle 10g the "First Letter Description" is empty! What is wrong with my code?

Try this, not complete, but with easy adjustments you can make it work the way you want:
FUNCTION last_is_vowel (string_in VARCHAR2)
RETURN BOOLEAN
IS
BEGIN
RETURN CASE WHEN LOWER(SUBSTR(string_in, -1)) IN ('a', 'e', 'i', 'o', 'u')
THEN TRUE
ELSE FALSE
END;
END last_is_vowel;

Look at your data. Chances are the first character in employees.last_name is capitalized. Remember, Oracle is case sensitive. You can user UPPER() or LOWER() to help find your match.
Also it'd be more efficient to search just for vowels and use an else statement for to find exclusions as João suggests.
SELECT last_name,
Substr(last_name, -1, 1) "Last character",
Substr(last_name, 1, 1) "First character",
CASE
WHEN lower(Substr(last_name, -1, 1)) IN ( 'a', 'e', 'i', 'o', 'u' ) THEN
'ends with a vowel'
ELSE
'does not end with a vowel'
END "Last Letter Description",
CASE
WHEN lower(Substr(last_name, 1, 1)) IN ( 'a', 'e', 'i', 'o', 'u' ) THEN
'starts with a vowel'
ELSE
'does not start with a vowel'
END "First Letter Description"
FROM employees
GROUP BY first_name,
last_name

Related

Ruby ZeroDivisionError

I am trying to create a encryption alghoritm in ruby. The encryption works fine, but the decryption part fails. The error is at line 67, and says the following:
decryption.rb:67:ln '/': divided by zero (ZeroDivisionError)
I have no idea why this is happening and i cannot find a answer to my question online.
This is the source code:
print ">"
ciphertext = gets.chomp
print ">"
symetricKey = gets.chomp
symetricKey.gsub! 'a', '1'
symetricKey.gsub! 'b', '2'
symetricKey.gsub! 'c', '3'
symetricKey.gsub! 'd', '4'
symetricKey.gsub! 'e', '5'
symetricKey.gsub! 'f', '6'
symetricKey.gsub! 'g', '7'
symetricKey.gsub! 'h', '8'
symetricKey.gsub! 'i', '9'
symetricKey.gsub! 'j', '10'
symetricKey.gsub! 'k', '11'
symetricKey.gsub! 'l', '12'
symetricKey.gsub! 'm', '13'
symetricKey.gsub! 'n', '14'
symetricKey.gsub! 'o', '15'
symetricKey.gsub! 'p', '16'
symetricKey.gsub! 'q', '17'
symetricKey.gsub! 'r', '18'
symetricKey.gsub! 's', '19'
symetricKey.gsub! 't', '20'
symetricKey.gsub! 'u', '21'
symetricKey.gsub! 'v', '22'
symetricKey.gsub! 'w', '23'
symetricKey.gsub! 'x', '24'
symetricKey.gsub! 'y', '25'
symetricKey.gsub! 'z', '26'
symetricKey=symetricKey.to_i
ciphertext.gsub! 'a', '1'
ciphertext.gsub! 'b', '2'
ciphertext.gsub! 'c', '3'
ciphertext.gsub! 'd', '4'
ciphertext.gsub! 'e', '5'
ciphertext.gsub! 'f', '6'
ciphertext.gsub! 'g', '7'
ciphertext.gsub! 'h', '8'
ciphertext.gsub! 'i', '9'
ciphertext.gsub! 'j', '10'
ciphertext.gsub! 'k', '11'
ciphertext.gsub! 'l', '12'
ciphertext.gsub! 'm', '13'
ciphertext.gsub! 'n', '14'
ciphertext.gsub! 'o', '15'
ciphertext.gsub! 'p', '16'
ciphertext.gsub! 'q', '17'
ciphertext.gsub! 'r', '18'
ciphertext.gsub! 's', '19'
ciphertext.gsub! 't', '20'
ciphertext.gsub! 'u', '21'
ciphertext.gsub! 'v', '22'
ciphertext.gsub! 'w', '23'
ciphertext.gsub! 'x', '24'
ciphertext.gsub! 'y', '25'
ciphertext.gsub! 'z', '26'
ciphertext = ciphertext.to_i
cleartext = ciphertext / (symetricKey / symetricKey / 100)
print"\n"
cleartext.to_s
cleartext.gsub! '1' ,'a'
cleartext.gsub! '2' ,'b'
cleartext.gsub! '3' ,'c'
cleartext.gsub! '4' ,'d'
cleartext.gsub! '5' ,'e'
cleartext.gsub! '6' ,'f'
cleartext.gsub! '7' ,'g'
cleartext.gsub! '8' ,'h'
cleartext.gsub! '9' ,'i'
cleartext.gsub! '10' ,'j'
cleartext.gsub! '11' ,'k'
cleartext.gsub! '12' ,'l'
cleartext.gsub! '13' ,'m'
cleartext.gsub! '14' ,'n'
cleartext.gsub! '15' ,'o'
cleartext.gsub! '16' ,'p'
cleartext.gsub! '17' ,'q'
cleartext.gsub! '18' ,'r'
cleartext.gsub! '19' ,'s'
cleartext.gsub! '20' ,'t'
cleartext.gsub! '21' ,'u'
cleartext.gsub! '22' ,'v'
cleartext.gsub! '23' ,'w'
cleartext.gsub! '24' ,'x'
cleartext.gsub! '25' ,'y'
cleartext.gsub! '26' ,'z'
puts cleartext
It doesn't work because the formula ciphertext / (symetricKey / symetricKey / 100) makes no sense at all.
symetricKey / symetricKey is always 1, divided by 100 that's always 0.01
symetricKey / symetricKey / 100 both operands are integers, so 0.01 is rounded down to 0
ciphertext / (symetricKey / symetricKey / 100) is equivalent to ciphertext / 0 (see 2.)
Your error is exactly what it says in the message: you're dividing by 0.
EDIT: As a small bonus, your code is broken anyway. 'k' for example is converted into 11, but when decrypting that will turn into 'aa'
Your question has been answered, but I'd like to suggest a more Ruby-like way to solve your problem.
If you look at the doc for Hash#gsub you will see that the second form of the method, written str.gsub(pattern, hash), where pattern is generally a regular expression and hash is, of course, a hash. Here's an example.
h = { 'c'=>'C', 'a'=>'A', 'n'=>'N', 'd'=>'D', 'o'=>'$', 'g'=>'G' }
'cat and dog.'.gsub(/./, h)
#=> "CAANDD$G"
/./ is a regular expression that simply matches any one character in str. It first matches 'c', then 'a', and so on. Consider the first letter, 'c'. Ruby checks to see if the hash h has a key 'c'. It does, so that character is replaced with the value of 'c' in the hash, 'C'. Next, 'a' is replaced with 'A'. h does not have a key 't', however, so Ruby converts 't' to an empty string. Similarly, the characters ' ' (a space) and '.' (a period) are not keys in h, so those characters are also converted to empty strings.
This form of gsub seems perfect for encrypting and decrypting strings.
Let's first construct the encoding hash.
arr = ('a'..'z').zip('01'..'26')
#=> [["a", "01"], ["b", "02"],..., ["z", "26"]]
encode = arr.to_h
#=> {"a"=>"01", "b"=>"02",..., "z"=>"26"}
encode[' '] = "27"
encode['.'] = "28"
So now
encode
#=> {"a"=>"01", "b"=>"02",..., "z"=>"26", " "=>"27", "."=>"." }
'a'..'z' and '01'..'2' are Ranges. See the docs for Enumerable#zip and Array#to_h. We would normally write those two lines as a single chained expression.
encode = ('a'..'z').zip('01'..'26').to_h
Notice that the values begin with "01", so that all are strings of the same length (2). If we started the values with "1" how could we decode the string "1226"? Would that be 'abbd' (1-2-3-4), 'abz' (1-2-26), 'lz' (12-26) or one of the other possibilities. That is not an issue if all the values of the hash encode are strings of length 2.
We could construct the hash for decoding in the same way( {'01'=>'a', '02'=>'b',...}), but it's easier to use the method Hash#invert:
decode = encode.invert
#=> {"01"=>"a", "02"=>"b",..., "26"=>"z", "27"=>" ", "28"=>"."}
If the string to be encrypted is
str = "how now, brown cow."
we can encode it with
encrypted = str.gsub(/./, encode)
#=> "081523271415232702181523142703152328"
which can then be decoded with
decoded = encrypted.gsub(/../, decode)
#=> "how now, brown cow."
Notice that the regular expression ("regex") for decoding matches any two characters at a time.
Two points. Firstly, we could use Hash#update (aka merge!) to write
encode = ('a'..'z').zip('01'..'26').to_h
encode.update( ' '=>"27", '.'=>"28" )
Ruby allows us to write encode.update({ ' '=>"27", '.'=>"28" }) without the braces (an example of syntactic sugar).
The better way is to use Hash#default_proc= to write
encode = ('a'..'z').zip('01'..'26').to_h
encode.default_proc = proc { |h,k| h[k] = k }
This is a bit complicated for a Ruby newbie, but the effect is to cause encode[k] to return k if encode does not have a key k. For example, encode['.'] #=> '.'.

ORA-32033: unsupported column aliasing

I have a query that is working on oracle 12c but not in 10g. I am not sure what the problem is:
My query is:
WITH tab1(rn,begin_chq_num,chq_lvs_stat,chq_num_of_lvs,tes) AS
(SELECT 1 rn,
begin_chq_num,
chq_lvs_stat,
chq_num_of_lvs,
SUBSTR(chq_lvs_stat,1,1) tes
FROM tbaadm.chq_book_table
WHERE del_flg != 'Y'
AND acid IN
(SELECT acid
FROM tbaadm.GENERAL_ACCT_MAST_TABLE
WHERE foracid = '01411110171546'
)
UNION ALL
SELECT rn + 1 rn,
begin_chq_num,
chq_lvs_stat,
chq_num_of_lvs,
SUBSTR(chq_lvs_stat,rn + 1,1) tes
FROM tab1
WHERE rn < chq_num_of_lvs
)
SELECT
CASE
WHEN begin_chq_num = 1
THEN rn
ELSE begin_chq_num +(rn-1)
END cheque_num,
begin_chq_num
||'-'
||(chq_num_of_lvs+begin_chq_num-1) cheque_range,
DECODE(tes, 'I', 'Issued', 'P', 'Cleared', 'U', 'Unused', 'S', 'Stopped', 'C', 'Cautioned', 'D', 'Destroyed', 'R', 'Returned Paid', 'T', 'Transfered') status
FROM tab1
ORDER BY chq_lvs_stat,
rn;
The error is :
ORA-32033: unsupported column aliasing
32033. 00000 - "unsupported column aliasing"
*Cause: column aliasing in WITH clause is not supported yet
*Action: specify aliasing in defintion subquery and retry
What should I do different?
In Oracle 10g, the sub-query factoring clause does not support column aliases or recursive sub-queries. The syntax you are using appears in 11gR2.
You need to change:
WITH tab1(rn,begin_chq_num,chq_lvs_stat,chq_num_of_lvs,tes) AS
To:
WITH tab1 AS
And find a different solution that does not use a recursive subquery factoring clause.
I think you could do this in Oracle 10g:
WITH tab1 AS (
SELECT l.COLUMN_VALUE rn,
begin_chq_num,
chq_lvs_stat,
chq_num_of_lvs,
SUBSTR(chq_lvs_stat,l.COLUMN_VALUE,1) tes
FROM tbaadm.chq_book_table t,
TABLE(
CAST(
MULTISET(
SELECT LEVEL
FROM DUAL
CONNECT BY LEVEL <= LENGTH( t.chq_lvs_stat )
)
AS SYS.ODCINUMBERLIST
)
) l
WHERE del_flg != 'Y'
AND acid IN ( SELECT acid
FROM tbaadm.GENERAL_ACCT_MAST_TABLE
WHERE foracid = '01411110171546'
)
)
SELECT CASE
WHEN begin_chq_num = 1
THEN rn
ELSE begin_chq_num +(rn-1)
END cheque_num,
begin_chq_num
||'-'
||(chq_num_of_lvs+begin_chq_num-1) cheque_range,
DECODE(
tes,
'I', 'Issued',
'P', 'Cleared',
'U', 'Unused',
'S', 'Stopped',
'C', 'Cautioned',
'D', 'Destroyed',
'R', 'Returned Paid',
'T', 'Transfered'
) status
FROM tab1
ORDER BY chq_lvs_stat, rn;

Adding additional columns to my Oracle SQL result

I have a SQL query built that returns a singular column of figures. Sample is shown below. I need to enhance this in a singular query and retrieve a 2nd set of figures using similar filters/parameters (instead of status=E I'd look for category=E). This query has gotten fairly complex for my knowledge though and I'm a bit stumped on how to approach adding this additional SELECT statement to get a 2nd column. Appreciate if anyone can point me in the right direction.
SELECT Count(eqnbr) EQUIP,
imp_exp,
'TITLE' TITLE
FROM (SELECT cy.container EQNbr,
cy.location_position "POS",
Substr(cy.location_position, 1, 1) Row_Nbr,
CASE
WHEN Substr(cy.location_position, 1, 3) IN (
'M01', 'N03', 'N04', 'N05',
'N06', 'N07', 'N08', 'N09' ) THEN
'Rail'
WHEN Substr(cy.location_position, 1, 1) IN ( 'F', 'G', 'H', 'J',
'K', 'L', 'M', 'P',
'R', 'S' ) THEN
'Locals'
WHEN Substr(cy.location_position, 1, 1) IN ( 'B', 'D' ) THEN
'Export'
ELSE Concat ('Row ', Substr(cy.location_position, 1, 1))
END IMP_EXP
FROM current_yard cy
WHERE eq_class = 'CTR'
AND location_position NOT LIKE 'CT%'
AND using_line NOT IN ( 'TEST', 'UNK', 'TST', 'B125',
'BO77', 'BR75' )
AND using_line IS NOT NULL
AND ( container NOT LIKE 'TEST%'
OR container NOT LIKE 'KENT%' )
AND Length(container) >= 10
AND status = 'E'
AND Substr(cy.location_position, 1, 1) NOT IN
( '1', '2', '3', '4',
'5', '6', '7', '8',
'9', '0', 'A', 'C',
'E', 'U', 'V', 'W', 'X' )) a
GROUP BY imp_exp
ORDER BY 2 ASC

Many Replace after each other in SELECT statement

I've a column that have a varchar2 like this: ..x...y...z..
I want to replace x to 1, y to 2 and z to 3.
Is it possible to have multiple replace after each other in select statement to replace these characters?
(select)
replace(varchar2, 'x', '1')
replace(varchar2, 'y', '2')
replace(varchar2, 'z', '3')
Or use TRANSLATE function if that fits your needs http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions216.htm#SQLRF06145
Do you mean something like this:
replace(replace(replace(varchar2, 'x', '1'), 'y', '2'), 'z', '3')

Encode (& decode) a URL as a string of letters

I want a function that can encode any URL into a string of all letters (upper and lowercase), and another function to decode it back into a URL. What's the best way to accomplish this?
Sample API:
> 'http://stackoverflow.com/questions/ask'.url_to_chars
=> 'mgzGBORuRcFSfNXDpDbVgzzvANHLqIEcgjCAXsKbNXGouOckToKkZRBnvE'
> 'mgzGBORuRcFSfNXDpDbVgzzvANHLqIEcgjCAXsKbNXGouOckToKkZRBnvE'.chars_to_url
=>'http://stackoverflow.com/questions/ask'
Base64 is a simple way to do this:
String encoded = Base64.encode("http://stackoverflow.com/questions/ask".getBytes());
System.out.println(encoded);
System.out.println(new String(Base64.decode(encoded)));
Prints:
aHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy9hc2s=
http://stackoverflow.com/questions/ask
Update:
If you actually look at the RFC 1738 URLs are case-insensitve and only a range of characters are allowed. There's plenty of space to map it as long as your input strings are valid encoded URLs.
import string
l = string.ascii_letters + string.digits
t = string.ascii_lowercase + string.digits + ";/?:#=&$-_.+!*'(),"
d = dict(zip(l,t))
e = dict(zip(t,l))
d and e are the decoding and the reverse encoding mapping.
[('a', 'a'), ('b', 'b'), ('c', 'c'), ('d', 'd'), ('e', 'e'), ('f', 'f'), ('g', 'g'), ('h', 'h'), ('i', 'i'), ('j', 'j'), ('k', 'k'), ('l', 'l'), ('m', 'm'), ('n', 'n'), ('o', 'o'), ('p', 'p'), ('q', 'q'), ('r', 'r'), ('s', 's'), ('t', 't'), ('u', 'u'), ('v', 'v'), ('w', 'w'), ('x', 'x'), ('y', 'y'), ('z', 'z'), ('0', 'A'), ('1', 'B'), ('2', 'C'), ('3', 'D'), ('4', 'E'), ('5', 'F'), ('6', 'G'), ('7', 'H'), ('8', 'I'), ('9', 'J'), (';', 'K'), ('/', 'L'), ('?', 'M'), (':', 'N'), ('#', 'O'), ('=', 'P'), ('&', 'Q'), ('$', 'R'), ('-', 'S'), ('_', 'T'), ('.', 'U'), ('+', 'V'), ('!', 'W'), ('*', 'X'), ("'", 'Y'), ('(', 'Z'), (')', '0'), (',', '1')]
Decode and encode are only simple mappings:
def encode(s): return ''.join(e[c] for c in s)
def decode(s): return ''.join(d[c] for c in s)
The output is:
enc = encode("http://stackoverflow.com/questions/ask")
>>> decode(enc)
'http://stackoverflow.com/questions/ask'
>>> enc
'httpNLLstackoverflowUcomLquestionsLask'
You can make use of base64 encoding and decoding.
Depending on the data you can use some encryption and decryption algorithm to accomplish this. It will put the string into text with no special characters etc. With the added bonus that the data is encrypted.

Resources