-- bad
SELECT * FROM foo order by bar;
-- good
SELECT * FROM foo ORDER BY bar;
-- bad
SELECT COUNT(*) FROM foo;
-- good
SELECT count(*) FROM foo;
-- bad
CREATE TABLE foo(bar INTEGER, baz TEXT);
-- good
CREATE TABLE foo(bar integer, baz text);
Do not use quotation marks for identifiers, unless you are defining a new type (which needs camelCase notation).
-- bad
UPDATE "foo" SET "bar" = x;
-- good
UPDATE foo SET bar = x;
-- good
CREATE TYPE foo AS (
"fooId" integer,
"title" text,
"parentId" integer
);
-- bad
SELECT baz FROM foo WHERE bar <> baz;
-- good
SELECT bar FROM foo WHERE bar != baz;
-- bad
SELECT 'foo' || 'bar';
-- good
SELECT concat('foo', 'bar');
-- bad
SELECT cast('bar' AS integer);
-- good
SELECT 'bar'::integer;
-- only for immutable functions
CREATE FUNCTION foo() RETURNS text IMMUTABLE AS $$
SELECT integer 'bar';
$$ LANGUAGE sql ;
-- bad
SELECT '{1, 2, 3 + 4}';
-- bad
SELECT array[1,2,3+4];
-- good
SELECT ARRAY[1, 2, 3 + 4];
-- bad
CREATE FUNCTION foo(text) RETURNS text AS $$
SELECT $1;
$$ LANGUAGE sql;
-- bad
CREATE FUNCTION foo(bar text) RETURNS text AS $$
SELECT bar;
$$ LANGUAGE sql;
-- good
CREATE FUNCTION foo(in_bar text) RETURNS text AS $$
SELECT in_bar;
$$ LANGUAGE sql;
-- bad
CREATE FUNCTION foo(in_bar text = 'bar') RETURNS text AS $$
SELECT in_bar;
$$ LANGUAGE sql;
-- good
CREATE FUNCTION foo(in_bar text DEFAULT 'bar') RETURNS text AS $$
SELECT in_bar;
$$ LANGUAGE sql;
CREATE FUNCTION foo(in_a integer, in_b integer, in_c integer) RETURNS text AS $$
SELECT in_a;
SELECT in_b;
SELECT in_c;
$$ LANGUAGE sql;
-- bad
SELECT foo(1, 2, 3);
-- good
SELECT foo(in_a := 1, in_b := 2, in_c := 3);
-- if needed
SELECT foo(in_c := 3, in_a := 1, in_b := 2);
--bad
SELECT foo FROM bars;
-- good
SELECT foo FROM bar;
CREATE TABLE foo(foo_id serial);
CREATE TABLE bar(bar_id serial);
-- wrong
CREATE TABLE foo_bar(foo_id serial, bar_id serial);
-- good
CREATE TABLE join_foo_with_bar(foo_id serial, bar_id serial);
-- bad
CREATE TABLE nationality(nationality_id serial, title text);
-- good
CREATE TABLE ref_nationality(nationality_id serial, title text);
-- bad
CREATE TYPE foo AS ("barBaz" integer);
-- good
CREATE TYPE rt_foo AS ("barBaz" integer);
-- bad
CREATE TABLE foo(id serial);
-- good
CREATE TABLE foo(foo_id serial);
CREATE TABLE person (
birth_date timestamp,
denorm_age integer,
);
NULL
and NOT NULL
constraints must be declared into the table declaration without explicit column reference.
-- bad
CREATE TABLE foo(bar integer, NOT NULL (bar));
-- good
CREATE TABLE foo(bar integer NOT NULL);
-- bad
ALTER TABLE foo ADD CONSTRAINT foo_foo_id_pkey PRIMARY KEY (foo_id);
-- good
ALTER TABLE foo ADD CONSTRAINT pkey_foo PRIMARY KEY (foo_id);
Other constraints must be explicitly named based on the *key*_*table*_on_*column*(_and_*column*)
pattern.
Keys are: fkey
for FOREIGN KEY
, key
for UNIQUE
, check
for CHECK
.
CREATE TABLE foo(foo_id serial, bar_id integer);
-- bad
ALTER TABLE foo ADD CONSTRAINT foo_bar_id_fkey FOREIGN KEY bar_id REFERENCES bar(bar_id);
-- good
ALTER TABLE foo ADD CONSTRAINT fkey_foo_on_bar_id FOREIGN KEY bar_id REFERENCES bar(bar_id);
-- good
ALTER TABLE foo ADD CONSTRAINT check_foo_on_foo_id_and_bar_id CHECK (foo_id > bar_id);
-- bad
CREATE INDEX ON foo(bar, baz);
-- good
CREATE INDEX idx_foo_on_bar_and_baz ON foo(bar, baz);
-- bad
SELECT * FROM foo;
-- good
SELECT foo_id, bar_id, creation_date FROM foo;
CREATE TABLE foo(a, b default 0, c, d default 1);
-- bad
INSERT INTO foo VALUES (1, 2, 3, 4);
-- bad
INSERT INTO foo(a, c) VALUES (1, 3);
-- good
INSERT INTO foo(a, b, c, d) VALUES (1, 2, 3, 4);
-- good
INSERT INTO foo(a, b, c, d) VALUES (1, default, 3, default);
Do not use NATURAL JOIN
and JOIN USING
, it is unreliable. Use instead JOIN ON
.
-- bad
SELECT baz FROM foo NATURAL JOIN bar;
-- bad
SELECT baz FROM foo JOIN bar USING(foo_id);
-- good
SELECT baz FROM foo JOIN bar ON foo.foo_id = bar.foo_id;
-- bad
SELECT baz FROM foo INNER JOIN bar ON ...;
-- good
SELECT baz FROM foo JOIN bar ON ...;
Do not use NOT IN
, it never matches if there is but a single NULL
in the list.
-- bad
SELECT foo_id FROM foo WHERE foo_id NOT IN (SELECT foo_id FROM bar);
-- good
SELECT foo_id FROM foo WHERE NOT EXISTS (SELECT foo_id FROM bar);
-- bad
SELECT f.bar FROM foo f;
-- good
SELECT f.bar FROM foo AS f;
-- bad
CREATE TABLE foo ();
INSERT INTO bar (baz) VALUES (1);
INSERT INTO bar(baz) VALUES(1);
CREATE FUNCTION foo_bar (in_a text) ...;
-- good
CREATE TABLE foo();
INSERT INTO bar(baz) VALUES (1);
CREATE FUNCTION foo_bar(in_a text) ...;
-- bad
CREATE table foo
(
a,
b,
c
);
-- bad
CREATE table foo (
a
, b
, c
);
-- good
CREATE TABLE foo (
a,
b,
c
);
Respect proper function indentation, name the $$
block and use multi-line parameters only if needed.
-- good
CREATE FUNCTION foo(in_a text, in_b integer)
RETURNS integer
VOLATILE SECURITY INVOKER
AS $body$
SELECT foo_id FROM foo WHERE bar = in_a AND baz = in_b;
$body$ LANGUAGE sql;
-- if needed
CREATE FUNCTION foo (
in_a text,
in_b integer
)
RETURNS integer
VOLATILE SECURITY INVOKER
AS $body$
SELECT foo_id FROM foo WHERE bar = in_a AND baz = in_b;
$body$ LANGUAGE sql;
Respect proper query indentation. Each statements must be right-aligned for the same depth. Each depth must be aligned one space behind its parent and is independent in terms of statements' right-alignment.
-- good
SELECT foo_id
FROM foo
WHERE foo_id IN (
SELECT foo_id
FROM bar
);
-- good
SELECT f.data,
f.item,
f.category
FROM foo AS f
JOIN bar AS b
ON f.id = b.id
WHERE f.data > b.data
AND f.item > 0
GROUP BY f.category
HAVING count(*) > 0
ORDER BY f.rank
LIMIT 10;
-- good
WITH foo_with AS (
SELECT name,
sum(price) AS total_price,
product
FROM foo
GROUP BY name
),
bar_with AS (
SELECT name
FROM foo_with
WHERE total_foo > (
SELECT total / 10
FROM bar
)
);
-- good
ALTER TABLE foo
ADD CONSTRAINT fkey_foo_on_bar_id
FOREIGN KEY (bar_id)
REFERENCES bar(bar_id),
ADD CONSTRAINT check_foo_on_baz
CHECK (baz > 10);