NULL if any operand is NULL.SELECT 'Hello' || ' ' || 'World'; -- 'Hello World' SELECT 'Hi' || NULL; -- NULL ← entire result is NULL
||.SELECT CONCAT('Hello', ' ', 'World'); -- 'Hello World' SELECT CONCAT('Hi', NULL, '!'); -- 'Hi!' ← NULL silently skipped
| Expression | Result | Why |
|---|---|---|
'a' || NULL |
NULL | NULL propagates |
CONCAT('a', NULL) |
'a' | NULL treated as '' |
CONCAT_WS('-', 'a', NULL, 'b') |
'a-b' | NULL entries skipped entirely |
CONCAT_WS(separator, val1, val2, ...) joins non-NULL values with a separator.SELECT LENGTH('hello'); -- 5 SELECT LENGTH(NULL); -- NULL -- CHAR_LENGTH() is identical
SELECT LOWER('Hello WORLD'); -- 'hello world'
SELECT UPPER('Hello World'); -- 'HELLO WORLD'
SELECT INITCAP('hello world'); -- 'Hello World' SELECT INITCAP('JOHN DOE'); -- 'John Doe'
LPAD('42', 5, '0') → '00042' RPAD('hi', 5, '.') → 'hi...'
SELECT REVERSE('hello'); -- 'olleh' SELECT REPEAT('ab', 3); -- 'ababab'
LTRIM(' hi ') → 'hi ' LTRIM('xxHello', 'x') → 'Hello'
RTRIM(' hi ') → ' hi' RTRIM('Hello!!', '!') → 'Hello'
TRIM(' hi ') → 'hi' TRIM(LEADING 'x' FROM 'xxhi') → 'hi' TRIM(TRAILING '!' FROM 'hi!') → 'hi'
SELECT SUBSTRING('Hello World', 7, 5); -- 'World' (start=7, length=5) SELECT SUBSTR('abcdef', 2, 3); -- 'bcd'
SUBSTR() is an alias. SQL standard syntax: SUBSTRING(text FROM 7 FOR 5).LEFT('Hello', 3) → 'Hel' RIGHT('Hello', 3) → 'llo' LEFT('Hello', -2) → 'Hel' (skip last 2) RIGHT('Hello', -2) → 'llo' (skip first 2)
0 if not found.SELECT POSITION('World' IN 'Hello World'); -- 7 SELECT POSITION('xyz' IN 'Hello'); -- 0 (not found) -- STRPOS(text, substr) is equivalent: STRPOS('Hello World', 'World') → 7
SELECT REPLACE('hello world', 'world', 'SQL'); -- 'hello SQL' SELECT REPLACE('aabbcc', 'b', 'X'); -- 'aaXXcc' (all occurrences) -- To remove a substring, use '' as new: REPLACE('hello!!', '!', '') → 'hello'
REPLACE(), this works one character at a time, not on substrings.SELECT TRANSLATE('hello', 'el', 'ip'); -- 'hippo' (h unchanged, e→i, l→p, l→p, o unchanged) SELECT TRANSLATE('hello', 'el', 'i'); -- 'hio' (e→i, both l's deleted) -- Useful for stripping unwanted chars: TRANSLATE('(555)123-4567', '()-', '') → '5551234567'
REPEAT('ab', 3) → 'ababab' REPEAT('*', 5) → '*****' REPEAT('hi', 0) → ''
SPLIT_PART('a,b,c', ',', 2) → 'b' SPLIT_PART('2024-01-15', '-', 1) → '2024'
%s for strings, %I for identifiers, %L for literals.FORMAT('Hello %s!', 'World') → 'Hello World!' FORMAT('%s is %s', 'SQL', 'fun') → 'SQL is fun'
:::: operator is PostgreSQL shorthand for CAST().SELECT CAST('42' AS INTEGER); -- 42 SELECT '42'::INTEGER; -- 42 (shorthand) SELECT '3.14'::NUMERIC; -- 3.14 SELECT 42::TEXT; -- '42' SELECT '2024-01-15'::DATE; -- date value
-- Guard against division by zero: SELECT total / NULLIF(divisor, 0) FROM t; -- Returns NULL instead of ERROR when divisor = 0 NULLIF('', '') → NULL (treat empty as NULL) NULLIF(5, 5) → NULL NULLIF(5, 0) → 5
WHERE divisor != 0 to filter out zero rows entirely.ROUND(3.456) → 3 ROUND(3.456, 2) → 3.46 ROUND(3.5) → 4 ROUND(-3.5) → -4
CEIL(4.1) → 5 CEIL(4.0) → 4 CEIL(-4.7) → -4 (towards zero)
FLOOR(4.9) → 4 FLOOR(4.0) → 4 FLOOR(-4.1) → -5 (away from zero)
TRUNC(3.9) → 3 (NOT 4) TRUNC(-3.9) → -3 (towards zero) TRUNC(3.456, 2) → 3.45 (clip, not round)
TRUNC(3.9) = 3 but ROUND(3.9) = 4ABS(-42) → 42 ABS(42) → 42 ABS(-3.14) → 3.14
MOD(10, 3) → 1 (remainder) 10 % 3 → 1 (same as MOD) POWER(2, 8) → 256 SQRT(144) → 12 SIGN(-7) → -1 (-1, 0, or 1)
DATE_PART('year', '2024-07-15'::DATE) → 2024 DATE_PART('month', '2024-07-15'::DATE) → 7 DATE_PART('day', '2024-07-15'::DATE) → 15 DATE_PART('hour', NOW()) → current hour DATE_PART('dow', NOW()) → 0=Sun…6=Sat DATE_PART('epoch', NOW()) → Unix timestamp
DATE_PART(). Returns the same values with slightly different syntax. Prefer this for portability.EXTRACT(YEAR FROM hire_date) EXTRACT(MONTH FROM NOW()) EXTRACT(DOW FROM created_at) -- Practical example: SELECT * FROM orders WHERE EXTRACT(YEAR FROM order_date) = 2024;
NOW() → timestamp with timezone CURRENT_TIMESTAMP → same as NOW() CURRENT_DATE → today's date only CURRENT_TIME → current time only CLOCK_TIMESTAMP() → real time mid-transaction
CURRENT_DATE + INTERVAL '7 days' NOW() - INTERVAL '1 month' AGE(end_date, start_date) → interval DATE_TRUNC('month', NOW()) → first of month TO_CHAR(NOW(), 'YYYY-MM-DD') → '2024-07-15' TO_DATE('15-07-2024', 'DD-MM-YYYY')