I am testing a select statement containing a CASE expression and I need to add a WHILE / LOOP inside one of the WHEN conditions.
The logic from this statement will eventually be included inside a PL/SQL script but I want to know it´s working 100% before I include it in the procedural.
The logic serves to query a zip/postal code inside an XML package found in a clob column.
INTENDED ACTION:
if ZIP > 5 digits then remove everything after 5th char.
if ZIP < 5 digits then add ‘0’ until the length reaches 5 char.
else do nothing.
WHAT IS NEEDED:
The logic that adds a ‘0’ using contact() function needs to reiterate until the new zip reaches a length of 5 char. As it is, the query only adds up to one ‘0’, but this needs to repeat as many times as required for total char length to = ‘5’. My attempts at adding a LOOP or a WHILE all result in incorrect formating according to Oracle SQL.
QUERY:
SELECT ORDER_NUMBER,
EXTRACTVALUE(xmltype(PACKAGE), '/Package/fCustomerVO/invoiceAddress/zip') as "ZIPS_INV",
LENGTH(EXTRACTVALUE(xmltype(PACKAGE), '/Package/fCustomerVO/invoiceAddress/zip')) as "ZIPS_LEN",
CASE
/* add digits to zip WHILE/LOOP NEEDED HERE */
WHEN LENGTH(EXTRACTVALUE(xmltype(PACKAGE), '/Package/fCustomerVO/invoiceAddress/zip')) < 5
THEN concat(EXTRACTVALUE(xmltype(PACKAGE), '/Package/fCustomerVO/invoiceAddress/zip'), '0')
/* subtract digits to zip */
WHEN LENGTH(EXTRACTVALUE(xmltype(PACKAGE), '/Package/fCustomerVO/invoiceAddress/zip')) > 5
THEN substr(EXTRACTVALUE(xmltype(PACKAGE), '/Package/fCustomerVO/invoiceAddress/zip'), 1, 5)
ELSE
'correct format'
END as "FIXED_ZIP"
FROM quarantine;
Advertisement
Answer
You can do both operations at once with RPAD()
: this functions either pads the string, truncates it or leaves it untouched as per the target length.
So:
RPAD(
EXTRACTVALUE(xmltype(PACKAGE), '/Package/fCustomerVO/invoiceAddress/zip'),
5,
'0'
)
In your query:
SELECT
t.*,
LENGTH(zips_inv) zip_len,
RPAD(zip_inv, 5, '0') fixed_zip
CASE WHEN LENGTH(zips_inv) = 5
THEN 'correct format'
ELSE 'wrong format'
END zip_status
FROM (
SELECT
order_number,
EXTRACTVALUE(xmltype(PACKAGE), '/Package/fCustomerVO/invoiceAddress/zip') zips_inv
FROM quarantine
) t
I find that a subquery is useful here to avoid repeating the same lengthy expression multiple times. Also, separating the zip value from its status (correct or not) makes more sense to me.