Truncate a String To Max Length… (With Contextual Clue of Omission)

Today, I had a need to write a function that elegantly truncated a string to a given maximum length, but give the end user a contextual clue that some of the string has been removed. Generally this is done with ellipsis (…), but sometimes other clues can be given.

Here’s an English example of what I mean.

Original message :

At the zoo today we saw lions, tigers, elephants, a rhinoceroses and hippopotamuses.

Truncate string to 50 characters with contextual clue of omission :

At the zoo today we saw lions, tigers, elephants,…

Notice the “…” is a marker that signifies there is an omission, so it acts as an overflow marker. The overflow marker only comes into play if it exceeds the maximum allowed length.

Anyway, here’s what I came up with. To cover both character semantics (length and byte), I’ve included a character version and a byte version.


create or replace function StrMaxLength(pStr varchar2, pMaxLength pls_integer, pOverflowMarker varchar2 default '…') return varchar2 is
-- Truncates input string to max length of chars, using Overflow Marker as an indicator of omission if truncation occurred
begin
  if pMaxLength < 0 then
    raise_application_error(-20001, 'Max Length must be 0 or greater');
  end if;
  return case
           when pStr is null or coalesce(pMaxLength, 0) = 0 then null 
           when length(pStr) > pMaxLength then substr(pStr, 1, greatest(pMaxLength - coalesce(length(pOverflowMarker), 0), 0)) || substr(pOverflowMarker, 1, pMaxLength)
           else pStr
         end;
end;
/

create or replace function StrMaxLengthB(pStr varchar2, pMaxLength pls_integer, pOverflowMarker varchar2 default '…') return varchar2 is
-- Truncates input string to max length of bytes, using Overflow Marker as an indicator of omission if truncation occurred
begin
  if pMaxLength < 0 then
    raise_application_error(-20001, 'Max Length must be 0 or greater');
  end if;
  return case
           when pStr is null or coalesce(pMaxLength, 0) = 0 then null 
           when lengthB(pStr) > pMaxLength then substrb(pStr, 1, greatest(pMaxLength - coalesce(lengthb(pOverflowMarker), 0), 0)) || substrb(pOverflowMarker, 1, pMaxLength)
           else pStr
         end;
end;
/

Notes :
The greatest(…) bit ensures length is not negative, in cases where the overflow marker is longer than the maximum allowed length.
The reason I substr(pOverflowMarker…, …) to max length it to ensure the overflow marker itself doesn’t cause the output string to exceed the allowed length.

Here’s an example of its usage :

SQL> with data(str) as (
  2    select 'The quick brown fox jumped over a lazy dog' from dual
  3  )
  4  select *
  5  from (
  6    select level - 1 MaxLength,
  7           StrMaxLength(str, level - 1) str_def_overlow,
  8           StrMaxLength(str, level - 1, null) str_no_overlow,  
  9           StrMaxLength(str, level - 1, ' (more >>)') str_more_overlow
 10    from data
 11    connect by level <= LengthB(str) + 1
 12  )
 13  order by MaxLength desc;

 MAXLENGTH  STR_DEF_OVERLOW                               STR_NO_OVERLOW                                      STR_MORE_OVERLOW
----------  --------------------------------------------  --------------------------------------------  --------------------------------------------
        42  The quick brown fox jumped over a lazy dog    The quick brown fox jumped over a lazy dog    The quick brown fox jumped over a lazy dog
        41  The quick brown fox jumped over a lazy…       The quick brown fox jumped over a lazy do     The quick brown fox jumped over (more >>)
        40  The quick brown fox jumped over a laz…        The quick brown fox jumped over a lazy d      The quick brown fox jumped ove (more >>)
        39  The quick brown fox jumped over a la…         The quick brown fox jumped over a lazy        The quick brown fox jumped ov (more >>)
        38  The quick brown fox jumped over a l…          The quick brown fox jumped over a lazy        The quick brown fox jumped o (more >>)
        37  The quick brown fox jumped over a …           The quick brown fox jumped over a laz         The quick brown fox jumped  (more >>)
        36  The quick brown fox jumped over a…            The quick brown fox jumped over a la          The quick brown fox jumped (more >>)
        35  The quick brown fox jumped over …             The quick brown fox jumped over a l           The quick brown fox jumpe (more >>)
        34  The quick brown fox jumped over…              The quick brown fox jumped over a             The quick brown fox jump (more >>)
        33  The quick brown fox jumped ove…               The quick brown fox jumped over a             The quick brown fox jum (more >>)
        32  The quick brown fox jumped ov…                The quick brown fox jumped over               The quick brown fox ju (more >>)
        31  The quick brown fox jumped o…                 The quick brown fox jumped over               The quick brown fox j (more >>)
        30  The quick brown fox jumped …                  The quick brown fox jumped ove                The quick brown fox  (more >>)
        29  The quick brown fox jumped…                   The quick brown fox jumped ov                 The quick brown fox (more >>)
        28  The quick brown fox jumpe…                    The quick brown fox jumped o                  The quick brown fo (more >>)
        27  The quick brown fox jump…                     The quick brown fox jumped                    The quick brown f (more >>)
        26  The quick brown fox jum…                      The quick brown fox jumped                    The quick brown  (more >>)
        25  The quick brown fox ju…                       The quick brown fox jumpe                     The quick brown (more >>)
        24  The quick brown fox j…                        The quick brown fox jump                      The quick brow (more >>)
        23  The quick brown fox …                         The quick brown fox jum                       The quick bro (more >>)
        22  The quick brown fox…                          The quick brown fox ju                        The quick br (more >>)
        21  The quick brown fo…                           The quick brown fox j                         The quick b (more >>)
        20  The quick brown f…                            The quick brown fox                           The quick  (more >>)
        19  The quick brown …                             The quick brown fox                           The quick (more >>)
        18  The quick brown…                              The quick brown fo                            The quic (more >>)
        17  The quick brow…                               The quick brown f                             The qui (more >>)
        16  The quick bro…                                The quick brown                               The qu (more >>)
        15  The quick br…                                 The quick brown                               The q (more >>)
        14  The quick b…                                  The quick brow                                The  (more >>)
        13  The quick …                                   The quick bro                                 The (more >>)
        12  The quick…                                    The quick br                                  Th (more >>)
        11  The quic…                                     The quick b                                   T (more >>)
        10  The qui…                                      The quick                                      (more >>)
         9  The qu…                                       The quick                                      (more >>
         8  The q…                                        The quic                                       (more >
         7  The …                                         The qui                                        (more
         6  The…                                          The qu                                         (more
         5  Th…                                           The q                                          (mor
         4  T…                                            The                                            (mo
         3  …                                             The                                            (m
         2                                                Th                                             (
         1  T
         0 

43 rows selected.
 

CLOB Concatenation

Adding string data to a CLOB in Oracle can be a tad slow, when compared to other string concatenation situations.  I first became aware of this concatenation performance issue from my own coding experience, but also from threads on Oracle Technical Network and a blog post by Jonathan Lewis.

Continue reading