So I’m sitting here quietly trying to port some old Oracle 7 view definitions to PostgreSQL 7.4.2. The first few were pretty easy, then I ran into views which were using Oracle specific functions, like decode(). After a some searching I come to find out that this functionality is supported in PostgreSQL by the CASE clause. That turned out to be reasonably straight forward, but I still wasn’t getting correct data back from the view in PostgreSQL. So I trimmed the code back until I found the culprit, rtrim. So that you get an idea of what was happening here is some example code that demonstrates the problem:
SELECT rpad( rtrim(first_name) || ' ' || rtrim(middle_name) || ' ' || rtrim(last_name), 40 ) AS name FROM users WHERE user_id = 123
This seems innocent enough right? Wrong! For some reason this code was returning NULL even though I knew that there was data in the first_name and last_name columns in the table for that user. I couldn’t find any mention of this anywhere, but when concatenating strings like this, if rtrim is passed a NULL then it NULLS out the whole concatenated string! I don’t know why it does this, but it does. So how do you fix this you might wonder (I did)? One way (I’m hoping there might be other, read easier, ways) is to add a CASE clause checking to see if the value of the column is NULL before passing it to rtrim(). In my example above let us assume that first_name and last_name don’t allow NULL values, but middle_name does (because not everyone has a middle name, or they don’t want other people to know what it is), the resulting code for the CASE solution looks like this:
SELECT rpad( rtrim(first_name) || ' ' || CASE WHEN middle_name IS NULL THEN '' ELSE rtrim(middle_name) END || ' ' || rtrim(last_name), 40 ) AS name FROM users WHERE user_id = 123
After writing that out the first time I wasn’t sure it would work, I was worried the parser might not like having a CASE clause in the middle of an rpad between concatenated strings. I didn’t have anything to loose so I went ahead and ran it. Worked like a charm, spit back a string for the name even if the middle_name field was NULL. The moral of our story, beware the swinging battle axe that is rtrim()!
One reply on “PostgreSQL rtrim() Strangeness”
You might also want to look into the PG function ‘coalesce’ (from some old 7.2 docs):
COALESCE(value[, …])
The COALESCE function returns the first of its arguments that is not NULL. This is often useful to substitute a default value for NULL values when data is retrieved for display, for example:
SELECT COALESCE(description, short_description, ‘(none)’) …