Reputation: 261
I want to be able to do the following:
insert into myTable values ('myParamName', NULL, 'alskdjflas');
insert into myTable values ('myParamName', 'A', 'asdf');
BUT it needs to give an error when I run this after:
insert into myTable values ('myParamName', 'A', 'asdf2');
I also need to be able to do this:
select *
from parameters p
left join myTable mt on mt.parameter_id = p.parameter_id
and mt.visible_mask_substring = NULL
And this:
select *
from parameters p
left join myTable mt on mt.parameter_id = p.parameter_id
and mt.visible_mask_substring = 'A'
So I need to be able to LEFT JOIN
on the second column, but this cannot be done without making the second column a primary key, but it can't be a primary key because primary keys can't be null, but my data needs to have an optionally null 2nd column.
I am about a minute away from giving up and just inserting the word "NULL" in quotes simply so I can have the second column be a PK but allow it to be nulled (likely not a proper solution):
DROP TABLE myTable;
CREATE TABLE myTable
(
parameter_id varchar2(40),
visible_mask_substring varchar2(1),
someVal varchar2(50),
PRIMARY KEY (parameter_id, visible_mask_substring),
CONSTRAINT idek_ibfk_1
FOREIGN KEY (parameter_id) REFERENCES parameters (parameter_id)
);
insert into myTable values ('myParamName', 'NULL', 'alskdjflas');
insert into myTable values ('myParamName', 'A', 'asdf');
Upvotes: 1
Views: 55
Reputation: 94969
A primary key is after all just a unique constraint on certain not nullable columns in the table. You want a unique key on the columns parameter_id
and visible_mask_substring
. But unlike is common in SQL, you want to treat NULL in visible_mask_substring
as if it were just another particular value.
As visible_mask_substring
can contain any possible string, it is technically not possible to have a unique index on just these two columns and treating NULL as an additional value.
There are two solutions, both using function indexes:
If you know a value that will never ever be used, use that to represent NULL. E.g. the string '###NULL###'. The index would look like
create index idx on mytable
(
parameter_id,
nvl(visible_mask_substring, '###NULL###')
);
If you cannot guarantee that any value will never be used (or if you just want a clear universal solution), use three columns:
create unique index idx on mytable
(
parameter_id,
nvl(visible_mask_substring, 'NULL'),
decode(visible_mask_substring, null, 'NULL', 'NOTNULL')
);
Demo: https://dbfiddle.uk/8HwR8Hox
Upvotes: 1