Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Padding a string in Postgresql with rpad without truncating it

Using Postgresql 8.4, how can I right-pad a string with blanks without truncating it when it's too long?

The problem is that rpad truncates the string when it is actually longer than number of characters to pad. Example:

SELECT rpad('foo', 5);  ==> 'foo  ' -- fine
SELECT rpad('foo', 2);  ==> 'fo'    -- not good, I want 'foo' instead.

The shortest solution I found doesn't involve rpad at all:

SELECT 'foo' || repeat(' ', 5-length('foo'));  ==> 'foo  ' -- fine
SELECT 'foo' || repeat(' ', 2-length('foo'));  ==> 'foo'   -- fine, too

but this looks ugly IMHO. Note that I don't actually select the string 'foo' of course, instead I select from a column:

SELECT colname || repeat(' ', 30-length(colname)) FROM mytable WHERE ...

Is there a more elegant solution?

like image 560
dmoebius Avatar asked Aug 27 '12 18:08

dmoebius


3 Answers

found a slightly more elegant solution:

SELECT greatest(colname,rpad(colname, 2));

eg:

SELECT greatest('foo',rpad('foo', 5));  -- 'foo  ' 
SELECT greatest('foo',rpad('foo', 2));  -- 'foo'  

.


To explain how it works: rpad('foo',5) = 'foo ' which is > 'foo' (greatest works with strings as well as numbers) rpad('foo',2) = 'fo' which is < 'foo', so 'foo' is selected by greatest function.

if you want left-padded words you cant use greatest because it compares left-to-right (eg 'oo' with 'foo') and in some cases this will be greater or smaller depending on the string. I suppose you could reverse the string and use the rpad and reverse it back, or just use the original solution which works in both cases.

like image 185
TimoSolo Avatar answered Nov 08 '22 00:11

TimoSolo


how about this

select case when length(col) < x then rpad(col, x)
else col
end
from table
like image 22
rutu Avatar answered Nov 08 '22 00:11

rutu


If you don't want to write that repeat business all the time, just write your own function for it. Something like this:

create or replace function rpad_upto(text, int) returns text as $$
begin
    if length($1) >= $2 then
        return $1;
    end if;
    return rpad($1, $2);
end;
$$ language plpgsql;

or this:

create or replace function rpad_upto(text, int) returns text as $$
select $1 || repeat(' ', $2 - length($1));
$$ language sql;

Then you can say things like:

select rpad_upto(colname, 30) from mytable ...

You might want to consider what you want rpad_upto(null, n) to produce while you're at it. Both versions of rpad_upto above will return NULL if $1 is NULL but you can tweak them to return something else without much difficulty.

like image 8
mu is too short Avatar answered Nov 08 '22 01:11

mu is too short