dmoebius
dmoebius

Reputation: 994

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?

Upvotes: 14

Views: 9404

Answers (5)

Melissa Barnett
Melissa Barnett

Reputation: 50

PostgreSQL statement below is to right pad three place values and alter column data type to text for column 'columnname.' I used pycharm IDE to help construct statement. The statement will pad with 000.

I have been looking for a while to solve the same issue, except for left pad and I thought I would share.

alter table 'schema.tablename' alter column 'columnname' type text using rpad('columnname'::text,3,'0')

Upvotes: 0

Emery Lapinski
Emery Lapinski

Reputation: 1662

Assuming efficiency is not your biggest concern here:

select regexp_replace(format('%5s', 'foo'), '(\s*)(\S*)', '\2\1')
  1. format() left-pads the string to the desired width
  2. then regexp_replace moves any leading spaces to the end.

I guess that would fail if you have leading spaces in the strings and you want to preserve them. Also note that format() doesn't return null on null params.

Upvotes: 0

TimoSolo
TimoSolo

Reputation: 7325

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.

Upvotes: 18

rutu
rutu

Reputation: 41

how about this

select case when length(col) < x then rpad(col, x)
else col
end
from table

Upvotes: 4

mu is too short
mu is too short

Reputation: 434635

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.

Upvotes: 8

Related Questions