Once you can concatenate and substring in DB2 for z/OS, the next job is editing text in place: swap a company suffix, map punctuation, splice a code into the middle of an account number, or pad a report column with blanks. Five built-in scalar functions cover that work: REPLACE, TRANSLATE, INSERT, REPEAT, and SPACE. They look similar in a SELECT list, but they operate on different units—whole substrings, single characters, or a start-and-length window.
All five are scalar functions in schema SYSIBM. You can use them anywhere an expression is legal: SELECT lists, WHERE predicates, SET clauses, VALUES, and CHECK constraints that allow functions. They are not aggregate functions. Each call looks at one set of argument values and returns one string (or null).
| Function | What it edits | Typical call |
|---|---|---|
| REPLACE | Substring (can be many characters) | REPLACE(name, 'INC', 'LTD') |
| TRANSLATE | Single characters via from/to maps | TRANSLATE(phone, '', '()- ') |
| INSERT | Position + length slice, then splice | INSERT(code, 3, 2, 'XY') |
| REPEAT | Whole string copied n times | REPEAT('*', 8) |
| SPACE | n blank characters | SPACE(4) |
Null behaviour is consistent: if any argument is null, the result is null. That matters in COBOL host variables with null indicators and in outer joins where a missing name must not silently become an empty string. Empty strings and nulls are different; REPLACE of a non-null source with a found token still yields a non-null string, even if the replacement is zero length.
Encoding still applies. Character arguments keep an encoding scheme and CCSID. Mixing EBCDIC application data with Unicode columns forces conversion before the function runs. Binary strings are allowed for some of these functions (REPLACE and INSERT) but not for classic SBCS-oriented TRANSLATE maps. When a result would exceed the maximum length of the return type (typically VARCHAR up to 32704 bytes in these contexts), Db2 raises an error instead of silently truncating.
REPLACE searches source-string for every occurrence of search-string and substitutes replace-string. The search is not a regular expression and is not case-insensitive. It is a straight byte/character sequence match.
1REPLACE(source-string, search-string, replace-string)
If search-string never appears, Db2 returns source-string unchanged. Occurrences do not overlap in the usual left-to-right scan: after a replacement, scanning continues after the inserted text, so a replace-string that contains search-string is not immediately replaced again in that same pass.
1234SELECT REPLACE('DINING', 'N', 'VID') AS STEP1, REPLACE('MAINFRAME INC', 'INC', 'LTD') AS STEP2, REPLACE('A--B--C', '--', '') AS STRIP_DASHES FROM SYSIBM.SYSDUMMY1;
STEP1 is the classic IBM example: each N becomes VID, so DINING becomes DIVIDIVIDG. STEP2 shows a token swap for a legal name. STRIP_DASHES shows deletion: replace-string is empty, so double dashes vanish and A--B--C becomes ABC.
Result type follows the source (typically VARCHAR). The actual length is the source length plus occurrences times (length of replace minus length of search). Expanding 'N' to 'VID' in a long column can overflow VARCHAR; test with realistic data, not just a five-letter sample.
REPLACE does not take a start position. It always means “every match.” If you only want to change characters 4 through 6, use INSERT (or SUBSTR concatenation) instead. If you want to change every letter A into B regardless of neighbours, TRANSLATE is cheaper to reason about than REPLACE(col, 'A', 'B'), though both can work for a one-character search.
TRANSLATE returns a string in which selected characters have been mapped to other characters. Think of a pair of typewriter bars: from-string is the keys you press, to-string is the glyphs that print.
123TRANSLATE(expression) TRANSLATE(expression, to-string, from-string) TRANSLATE(expression, to-string, from-string, pad-character)
12345SELECT TRANSLATE('Hello') AS UPPERISH, TRANSLATE('ABC-123', '999', '123') AS MASK_DIGITS, TRANSLATE('A-B-C', '', '-') AS DASH_TO_BLANK, TRANSLATE('banana', 'X', 'an', '*') AS MAP_WITH_PAD FROM SYSIBM.SYSDUMMY1;
MASK_DIGITS turns 1, 2, and 3 into 9, so ABC-123 becomes ABC-999. DASH_TO_BLANK uses an empty to-string, so each dash maps to the default pad (blank): A-B-C becomes A B C. MAP_WITH_PAD shows a short to-string: 'a' maps to X, and 'n' has no matching to-character so it becomes the pad '*', producing bX*X*X.
TRANSLATE does not search for the sequence 'an'. It never treats from-string as a substring. That is the REPLACE versus TRANSLATE exam question. REPLACE('banana', 'an', 'X') replaces the two-character token an. TRANSLATE('banana', 'X', 'an') maps the letter a and the letter n independently.
Mixed SBCS/DBCS translation has extra rules: you cannot map a single-byte character to a multi-byte character (or the reverse) in the same from/to pair. Pad must be a valid single character for the string type. Graphic strings use graphic from/to/pad. If you need Unicode-aware case folding, prefer UPPER/LOWER with a locale rather than assuming one-argument TRANSLATE understands every alphabet.
The INSERT scalar function deletes length string units from source-string beginning at start, then inserts insert-string at that same start position. It is an in-string splice. It does not write rows.
1234INSERT(source-string, start, length, insert-string) INSERT(source-string, start, length, insert-string, CODEUNITS16) INSERT(source-string, start, length, insert-string, CODEUNITS32) INSERT(source-string, start, length, insert-string, OCTETS)
1234SELECT INSERT('ABCDE', 3, 2, 'XYZ') AS SPLICE, INSERT('ABCDE', 3, 0, 'XYZ') AS INJECT, INSERT('ABCDE', 3, 2, '') AS DELETE_ONLY FROM SYSIBM.SYSDUMMY1;
SPLICE starts at C, deletes two characters (CD), and puts XYZ in the hole: ABXYZE. INJECT deletes nothing (length 0) so XYZ is injected before C: ABXYZCDE. DELETE_ONLY removes CD and puts nothing back: ABE.
If start is just past the end of the source, the insert-string is effectively appended (after any required padding to reach start, using blanks for character data or hex zeros for binary). If start + length runs past the end, Db2 deletes only through the last existing unit. Always validate start against LENGTH(source) in application code when the position comes from a host variable.
COBOL programmers meet two different INSERT words in the same program: EXEC SQL INSERT INTO for DML, and INSERT(col, 1, 0, :PREFIX) in a SELECT or SET. Read the parentheses. Function INSERT always has a source string as the first argument. Statement INSERT always has INTO.
REPEAT(expression, integer) returns expression concatenated with itself integer times. The integer is the repeat count, not a byte length.
12345SELECT REPEAT('*', 5) AS STARS, REPEAT('AB', 3) AS ABABAB, REPEAT(LASTNAME, 2) FROM DSN8C10.EMP FETCH FIRST 3 ROWS ONLY;
REPEAT is the building block for simple padding when LPAD/RPAD are not the shape you want, and for generating test data. Watch the result length: REPEAT(CHAR(100), 400) will overflow. Compute LENGTH(expression) * count before using a large host-variable count in production SQL.
SPACE(numeric-expression) returns a VARCHAR of that many blank characters. The numeric argument is truncated to integer if it is decimal. SPACE(0) is empty. A negative argument is invalid. Null in, null out.
123SELECT 'A' CONCAT SPACE(4) CONCAT 'B' AS A____B, REPEAT(' ', 4) AS SAME_IDEA FROM SYSIBM.SYSDUMMY1;
SPACE(4) and REPEAT(' ', 4) both yield four blanks. SPACE states the intent more clearly in report SQL and in CONCAT expressions that rebuild fixed-width layouts (for example recreating an 80-byte print line from VARCHAR pieces). Do not use SPACE to mean “null.” Blanks are real characters; they compare equal to other blanks and they are not UNKNOWN in predicates.
Worked comparison on the same source 'A-123-X':
In UPDATE statements, these functions are expressions on the right of SET. They do not lock extra rows by themselves; locking follows the UPDATE. In predicates, wrapping a column in REPLACE or TRANSLATE usually prevents index matching on that column unless you have an expression index or generated column that matches. Prefer storing a canonical form (digits-only phone, upper name) in a real column if you filter on it all day.
Imagine a row of alphabet fridge magnets. REPLACE is “every time you see the word CAT, swap in DOG.” TRANSLATE is “every letter C becomes a K, every letter A becomes an O” — one magnet at a time, using a cheat sheet. INSERT is “take out three magnets starting at slot 4 and push these new magnets into that gap.” REPEAT is “copy this magnet word five times in a row.” SPACE is “put this many empty magnet slots (blanks) here.” None of these is the same as walking to the fridge and sticking a whole new row of magnets on a different door — that other job is the INSERT INTO statement that adds table rows.
1. How does REPLACE differ from TRANSLATE?
2. What does the INSERT scalar function do?
3. What does SPACE(5) return?
4. What happens if search-string is not found in REPLACE?
5. What does TRANSLATE(string) with one argument do?