You can use functions to obtain PRIMARY KEY
s by using GENERATED
(or COMPUTED
or CALCULATED
and sometimes VIRTUAL
) fields. However, the virtual keyword also refers to the storage class (STORED
or VIRTUAL
) meaning that the generated field is either kept on disk or calculated on-the-fly.
See the fiddle here:
You can have your (licenceID
, YEAR(paymentDate
), MONTH(paymentDate
)) as the PRIMARY KEY
as follows:
CREATE TABLE t
(
i INT,
a DATE,
a_y SMALLINT GENERATED ALWAYS AS (YEAR(a)) STORED,
a_m SMALLINT GENERATED ALWAYS AS (MONTH(a)) STORED,
CONSTRAINT t_pk PRIMARY KEY (i, a_y, a_m)
);
and then test:
INSERT INTO t (i, a) VALUES (1, NOW()); ✓
INSERT INTO t (i, a) VALUES (1, DATE_ADD(NOW(), INTERVAL 1 MONTH)); ✓
INSERT INTO t (i, a) VALUES (2, now()); ✓
but:
INSERT INTO t (i, a) VALUES (1, '2021-10-30');
gives
Duplicate entry '1-2021-10' for key 't.PRIMARY'
Creating a table with a PRIMARY KEY
using direct calls to the functions isn't possible:
CREATE TABLE s
(
i INT,
a DATE,
a_y SMALLINT GENERATED ALWAYS AS (YEAR(a)) STORED,
a_m SMALLINT GENERATED ALWAYS AS (MONTH(a)) STORED,
CONSTRAINT t_pk PRIMARY KEY (i, (YEAR(a)), (MONTH(a)))
);
gives:
The primary key cannot be a functional index
Doesn't work in PostgreSQL either. In MySQL, it won't work for the VIRTUAL
storage class (which PostgreSQL doesn't support anyway).