In expressions, NULL means 'unknown', and anything combined with unknown is unknown — one NULL field in a five-term formula nulls the result. But this is an operator rule, not a law of nature: functions define their own NULL behavior, and concat() treating NULL as empty-string is the one everyone meets first. Neither is wrong; not knowing which you're getting is.
SELECT grade, grade || '-' || barrelAS label FROM batches ORDER BY grade;
SELECT grade, concat(grade, '-', COALESCE(barrel, 'loose')) AS label FROM batches ORDER BY grade;
The batch label for the NULL barrel came out NULL — the || operator propagates NULL through the whole expression, while concat() skips NULLs and COALESCE supplies a stated default.
COALESCE per field with a meant default; know each function's policy (|| propagates, concat skips).
|| propagates NULL everywhere; concat() skips NULLs in DuckDB/Postgres/MySQL — check yours.