SQL differences

CONCAT With a NULL Argument Returns NULL on MySQL and Skips It on PostgreSQL

A customer list built with CONCAT(first_name, ' ', last_name) looks complete on PostgreSQL and SQLite. Moved to MySQL or MariaDB, the same query returns NULL for some customers.

A person without a last name comes out as 'Ann ' on SQLite and PostgreSQL and as NULL on MySQL and MariaDB, so a list of names quietly loses entries there. CONCAT_WS skips NULL arguments on all four engines.

SELECT CONCAT(first_name, ' ', last_name) FROM people, run on four engines: SQLite 3.45.1 'Ann '; PostgreSQL 16.15 'Ann '; MySQL 8.0.46 NULL; MariaDB 10.11.14 NULL.

What Each Engine Answered

On a table made with

CREATE TABLE people (first_name VARCHAR(20), last_name VARCHAR(20));
INSERT INTO people VALUES ('Ann', NULL);

the example

SELECT CONCAT(first_name, ' ', last_name) FROM people;

gave these answers:

Engine Answer
SQLite 3.45.1 'Ann '
PostgreSQL 16.15 'Ann '
MySQL 8.0.46 NULL
MariaDB 10.11.14 NULL

These answers need SQLite 3.44 or later.

What to Write Instead

This form answers the same on every engine:

SELECT CONCAT(COALESCE(first_name, ''), ' ', COALESCE(last_name, '')) FROM people;
Engine Answer
SQLite 3.45.1 'Ann '
PostgreSQL 16.15 'Ann '
MySQL 8.0.46 'Ann '
MariaDB 10.11.14 'Ann '

Wrap every argument that can be NULL in COALESCE(x, '').

What BareSQL Portable Reports

Saved as example.sql, the example gets this from baresql lint --all:

$ baresql lint --all example.sql
example.sql:3:8: warning: CONCAT skips NULL arguments on SQLite and PostgreSQL. On MySQL and MariaDB one NULL makes the whole result NULL. [concat-null]
    CONCAT(first_name, ' ', last_name)
    Wrap every argument that can be NULL in COALESCE(x, '').

1 problem: 1 warning.

baresql rules concat-null prints the same answers in the terminal, and the BareSQL Portable page lists every difference BareSQL knows.