OP finds "... using null
values as representation of no present data is not a good idea, ..."
(This may be opinion based.)
I totally disagree with that assertion. NULL values have some significant advantages. It is a very good idea to use the built-in native support that SQL provides for NULL values.
Typically, the NULL value is described as representing an "unknown" value.
Yes, there are some quirks in dealing with NULL value you need to be aware of. An equality or inequality comparison with a NULL value returns NULL, not TRUE or FALSE. We just need to be aware that in SQL, boolean logic is tri-valued, and NULL will never equal TRUE and never equal FALSE.
These quirks are actually what make NULL value so very powerful.
If you want to use some mechanism other than NULL to represent "no data", that would require either...
storing a non-NULL "special" value that represents a "no-data" condition, and additional logic to check and operate on the "special" value.
storing a non-NULL "no data" indicator/flag in a second column, and additional logic to handle populating, checking and operating on that second column, in conjunction with the first.
And then you'll need to also come up with dummy "no data" rows in tables referenced by foreign keys, so the non-NULL "no data" values in your foreign key columns have a row to reference. Which is what I am thinking you were asking in your question...
If you want to declare your foreign key columns NOT NULL, and have a default value when no value is supplied, that default value will need to reference a row in the referenced table.
As a demonstration of this type of approach... NOTE: I am NOT advocating this as an appropriate design... as just a demonstration of "working around" using a NULL value to represent "no data".
create table favcolor
( id int not null primary key
, favcolor_name varchar(30) not null
);
create table user
( id int not null primary key
, favcolor_id int not null default '1' comment 'fk, ref favcolor.id'
, constraint FK_user_favcolor foreign key (favcolor_id) references favcolor(id)
);
insert into favcolor (id, favcolor_name) values (1, 'not chosen');
Once you get all of that done, you are going to discover the same thing that SQL Designers of old did. It would be very beneficial to have this kind of handling of "unknown", "no data", "unchosen" as a native built-in function of SQL. Which is why the NULL value was introduced in the first place, as a solution to this very type of problem.