Almost every DB2 for z/OS program trims a name, concatenates an account key, or takes the first three characters of a code. Those jobs use string functions: scalar functions on character, graphic, and binary data. This overview maps the categories, the return types you should expect, null behaviour, and CCSID / string-unit rules. Later pages drill into SUBSTR, CONCAT, TRIM, LOCATE, UPPER, and REPLACE.
IBM’s SQL Reference lists dozens of scalars. Group them by job so you can find the right name:
| Category | Examples (z/OS) |
|---|---|
| Slice / pad | SUBSTR, SUBSTRING, LEFT, RIGHT, INSERT, REPEAT, SPACE, LPAD, RPAD |
| Concatenate | CONCAT, || |
| Trim | TRIM, STRIP, LTRIM, RTRIM |
| Search / length | LOCATE, POSITION, LENGTH, OCTET_LENGTH, CHARACTER_LENGTH |
| Case / translate | UPPER, UCASE, LOWER, TRANSLATE, REPLACE |
| Convert / represent | CHAR, VARCHAR, HEX, DIGITS, CHR, ASCII_CHR, ASCII_STR, UNICODE_STR |
| Phonetic | SOUNDEX, DIFFERENCE |
SUBSTR(string, start [, length]) takes a substring on a byte-count basis for character and binary strings (a graphic “character” is a DBCS character). Start is 1-based. Mixed EBCDIC data can be split in the middle of a shift-out/shift-in sequence because SUBSTR does not parse mixed encoding.
SUBSTRING(string, start, length, CODEUNITS16 | CODEUNITS32 | OCTETS) is the Unicode-aware cousin. Use CODEUNITS32 when “two characters” must mean two letters even if one is ü or a supplementary character.
1234SELECT SUBSTR(FIRSTNME, 1, 3) AS FIRST3, SUBSTRING(FIRSTNME, 1, 2, CODEUNITS32) AS FIRST2_CHARS FROM DSN8C10.EMP WHERE EMPNO = '000130';
LEFT / RIGHT (and STRLEFT / STRRIGHT) take a prefix or suffix. INSERT splices a string into another. REPEAT / SPACE build filler. LPAD / RPAD pad to a length.
CONCAT(x, y) and the || operator join two strings. Types must be compatible (character with character, graphic with graphic, binary with binary, with documented promotions). Numeric arguments are often cast to VARCHAR first. Concatenation of many pieces is nested CONCAT or a chain of ||.
123SELECT CONCAT(CONCAT(FIRSTNME, ' '), LASTNAME) AS FULL_NAME, FIRSTNME || ' ' || LASTNAME AS FULL_NAME2 FROM DSN8C10.EMP;
STRIP and TRIM remove leading and/or trailing characters (often blank). LTRIM / RTRIM are the one-sided forms. Default strip character is blank, but TRIM can name another character. CHAR columns are padded with blanks to the length attribute—TRIM is how reports stop looking like “SMITH ”.
LOCATE / POSITION find the start of a substring. LENGTH returns a large integer length whose unit depends on the type (bytes for character/binary, DBCS characters for graphic). OCTET_LENGTH is explicitly bytes. CHARACTER_LENGTH (CHAR_LENGTH) can specify string units like SUBSTRING.
UPPER / UCASE and LOWER fold case according to the CCSID’s case mapping—not always a naive ASCII +32. TRANSLATE maps characters; REPLACE substitutes substrings.
CHAR and VARCHAR convert dates, numbers, and strings to character form (format options on CHAR for dates). HEX shows bytes. DIGITS is the character form of a number’s digits. CHR / ASCII_CHR build a character from a code point. ASCII_STR / EBCDIC_STR / UNICODE_STR move among encodings with substitution for unmappable characters.
Matching the input family is the default for slice-style functions (IBM’s SUBSTRING table is the pattern):
| Input family | Typical result |
|---|---|
| CHAR / VARCHAR | VARCHAR (sometimes CHAR from CHAR()) |
| CLOB | CLOB |
| GRAPHIC / VARGRAPHIC | VARGRAPHIC |
| DBCLOB | DBCLOB |
| BINARY / VARBINARY | VARBINARY |
| BLOB | BLOB |
| Numeric / datetime into CHAR/VARCHAR | CHAR or VARCHAR with a CCSID from string rules |
CLOB in, CLOB out keeps you in the LOB family—do not SUBSTR a 10 MB CLOB into a VARCHAR(10) without a length that fits. VARCHAR has a maximum length (32 704 bytes of UTF-8 representation in many contexts); exceeding it is an error.
Mixed data input: SUBSTRING says if the first argument is mixed data, the result is mixed; otherwise SBCS (for character). Graphic stays graphic. Bit data stays bit data on VARCHAR of bit data.
The rule to tattoo on your wrist: if any argument is null, the result is null for the ordinary string scalars (SUBSTR, SUBSTRING, CONCAT, LENGTH, UPPER, TRIM, LOCATE, …).
1234567-- If MIDINIT is null, full name is null — not 'HAAS' with a gap SELECT FIRSTNME || MIDINIT || LASTNAME FROM DSN8C10.EMP; -- Treat null middle initial as empty SELECT FIRSTNME || COALESCE(MIDINIT, '') || LASTNAME FROM DSN8C10.EMP;
Empty string '' is a real zero-length value. TRIM of all blanks can produce empty string, which is still NOT NULL if the column/expression is not null. That empty string is what LENGTH = 0 sees.
A CCSID identifies the encoding of a string: EBCDIC 37, UTF-8 1208, UTF-16 graphic 1200, and so on. String functions do not throw encodings away; they either preserve the input CCSID or assign one from encoding-scheme rules.
SUBSTR, SUBSTRING, and similar slices: CCSID of the result is the CCSID of the first argument. You are cutting the same byte stream, not translating it.
CHAR, VARCHAR, ASCII_STR, UNICODE_STR, concatenation of mixed schemes: Db2 applies encoding scheme and CCSID rules for strings. Unicode constants in SQL text, EBCDIC columns, and UTF-16 graphic columns can meet in one expression. The result CCSID is defined; if a character cannot be mapped, you get substitution characters or an error depending on the function and settings.
| Unit | Meaning |
|---|---|
| OCTETS | Bytes. Safe for binary and for “storage length” thinking; dangerous mid-character on UTF-8 |
| CODEUNITS16 | UTF-16 code units. Supplementary characters count as two units |
| CODEUNITS32 | Unicode scalar values (characters). Jürgen’s ü is one unit |
IBM’s SUBSTRING example uses FIRSTNAME = Jürgen. SUBSTRING(..., 1, 2, CODEUNITS32) keeps two characters (Jü). A byte-oriented SUBSTR of length 2 on UTF-8 can split ü and return an invalid fragment. On EBCDIC SBCS English data, OCTETS and “characters” coincide and beginners never notice. On Unicode columns they do not.
FOR BIT DATA and BINARY/VARBINARY are not text. HEX is the readable dump. Do not UPPER bit data expecting letters. VARCHAR of bit data remains bit data. Concatenating bit data with ordinary character data is a type/CCSID mistake—keep the families separate.
LENGTH of graphic data is in double-byte characters. A UTF-16 supplementary character takes two DBCS code units and counts as two for LENGTH. CHARACTER_LENGTH with CODEUNITS32 is the “user perceived character” count when you need it.
123456SELECT LENGTH(FIRSTNME) AS LEN_BYTES_OR_CHARS, OCTET_LENGTH(FIRSTNME) AS LEN_OCTETS, LENGTH(HIREDATE) AS LEN_DATE_INTERNAL, -- 4 for DATE LENGTH(CHAR(HIREDATE, EUR)) AS LEN_DATE_CHAR -- 10 for EUR FROM DSN8C10.EMP WHERE EMPNO = '000280';
LENGTH(DATE) is 4 (internal date length), not 10. LENGTH(CHAR(date, EUR)) is 10. That is a CCSID-and-representation lesson: functions see the type you pass, not the picture on the QMF screen.
Predicates like LIKE are not functions but they share CCSID and mixed-data issues. Keep pattern literals in the same encoding family as the column.
A string is a row of beads on a wire. Some beads are letters, and in Unicode one letter might be two beads glued together. SUBSTR counts beads (bytes). SUBSTRING ... CODEUNITS32 counts letters. CONCAT ties two wires together. TRIM pulls blank beads off the ends. LENGTH counts how many beads are left. If someone hands you “no wire” (null), you do not get an empty wire—you get “nothing,” and every toy that needed a wire also becomes nothing. The paint color on the beads is the CCSID: mixing a box of EBCDIC beads with Unicode beads means Db2 repaints some of them so they match.
1. If any argument to SUBSTR is null, the result is:
2. What is the usual CCSID of a SUBSTR result?
3. Why does IBM provide both SUBSTR and SUBSTRING?
4. LENGTH of a VARCHAR value returns:
5. CONCAT of a CHAR column and a Unicode literal may: