SQL Column definition: default value and not null redundant? - sql

I've seen many times the following syntax which defines a column in a create/alter DDL statement:
ALTER TABLE tbl ADD COLUMN col VARCHAR(20) NOT NULL DEFAULT "MyDefault"
The question is: since a default value is specified, is it necessary to also specify that the column should not accept NULLs? In other words, doesn't DEFAULT render NOT NULL redundant?

DEFAULT is the value that will be inserted in the absence of an explicit value in an insert / update statement. Lets assume, your DDL did not have the NOT NULL constraint:
ALTER TABLE tbl ADD COLUMN col VARCHAR(20) DEFAULT 'MyDefault'
Then you could issue these statements
-- 1. This will insert 'MyDefault' into tbl.col
INSERT INTO tbl (A, B) VALUES (NULL, NULL);
-- 2. This will insert 'MyDefault' into tbl.col
INSERT INTO tbl (A, B, col) VALUES (NULL, NULL, DEFAULT);
-- 3. This will insert 'MyDefault' into tbl.col
INSERT INTO tbl (A, B, col) DEFAULT VALUES;
-- 4. This will insert NULL into tbl.col
INSERT INTO tbl (A, B, col) VALUES (NULL, NULL, NULL);
Alternatively, you can also use DEFAULT in UPDATE statements, according to the SQL-1992 standard:
-- 5. This will update 'MyDefault' into tbl.col
UPDATE tbl SET col = DEFAULT;
-- 6. This will update NULL into tbl.col
UPDATE tbl SET col = NULL;
Note, not all databases support all of these SQL standard syntaxes. Adding the NOT NULL constraint will cause an error with statements 4, 6, while 1-3, 5 are still valid statements. So to answer your question: No, they're not redundant.

Even with a default value, you can always override the column data with null.
The NOT NULL restriction won't let you update that row after it was created with null value

My SQL teacher said that if you specify both a DEFAULT value and NOT NULLor NULL, DEFAULT should always be expressed before NOT NULL or NULL.
Like this:
ALTER TABLE tbl ADD COLUMN col VARCHAR(20) DEFAULT "MyDefault" NOT NULL
ALTER TABLE tbl ADD COLUMN col VARCHAR(20) DEFAULT "MyDefault" NULL

I would say not.
If the column does accept null values, then there's nothing to stop you inserting a null value into the field. As far as I'm aware, the default value only applies on creation of a new row.
With not null set, then you can't insert a null value into the field as it'll throw an error.
Think of it as a fail safe mechanism to prevent nulls.

In other words, doesn't DEFAULT render NOT NULL redundant ?
No, it is not redundant. To extended accepted answer. For column col which is nullable awe can insert NULL even when DEFAULT is defined:
CREATE TABLE t(id INT PRIMARY KEY, col INT DEFAULT 10);
-- we just inserted NULL into column with DEFAULT
INSERT INTO t(id, col) VALUES(1, NULL);
+-----+------+
| ID | COL |
+-----+------+
| 1 | null |
+-----+------+
Oracle introduced additional syntax for such scenario to overide explicit NULL with default DEFAULT ON NULL:
CREATE TABLE t2(id INT PRIMARY KEY, col INT DEFAULT ON NULL 10);
-- same as
--CREATE TABLE t2(id INT PRIMARY KEY, col INT DEFAULT ON NULL 10 NOT NULL);
INSERT INTO t2(id, col) VALUES(1, NULL);
+-----+-----+
| ID | COL |
+-----+-----+
| 1 | 10 |
+-----+-----+
Here we tried to insert NULL but get default instead.
db<>fiddle demo
ON NULL
If you specify the ON NULL clause, then Oracle Database assigns the DEFAULT column value when a subsequent INSERT statement attempts to assign a value that evaluates to NULL.
When you specify ON NULL, the NOT NULL constraint and NOT DEFERRABLE constraint state are implicitly specified.

In case of Oracle since 12c you have DEFAULT ON NULL which implies a NOT NULL constraint.
ALTER TABLE tbl ADD (col VARCHAR(20) DEFAULT ON NULL 'MyDefault');
ALTER TABLE
ON NULL
If you specify the ON NULL clause, then Oracle Database assigns the
DEFAULT column value when a subsequent INSERT statement attempts to
assign a value that evaluates to NULL.
When you specify ON NULL, the NOT NULL constraint and NOT DEFERRABLE
constraint state are implicitly specified. If you specify an inline
constraint that conflicts with NOT NULL and NOT DEFERRABLE, then an
error is raised.

Related

DB2 SQL Insert NULL into NOT NULL WITH DEFAULT

I faced a problem when inserting a NULL value into a column defined as NOT NULL WITH DEFAULT values.
In this example, I removed most of the columns for illustration purposes.
CREATE TABLE
FKTIM04
(
OBJECTID CHARACTER(32) NOT NULL,
UP_CHANGE_CL CHARACTER(1) DEFAULT '1' NOT NULL,
UP_CTRL_CL CHARACTER(1) DEFAULT '0' NOT NULL,
CONSTRAINT PK_FKTIM04 PRIMARY KEY (OBJECTID)
);
When I execute this SQL statement, there is an error:
INSERT INTO KTI.FKTIM04 (
UP_Change_CL
,UP_ctrl_CL
,ObjectID
)
VALUES (
NULL
,NULL
,'UMSTM0LW8A8Z50DT4WA7U93EEQDRXRTH'
)
Error:
[Code: -407, SQL State: 23502] Assignment of a NULL value to a NOT
NULL column "TBSPACEID=2, TABLEID=1298, COLNO=46" is not allowed..
SQLCODE=-407, SQLSTATE=23502, DRIVER=4.22.29
I know that the column is defined as NOT NULL. If it tries to insert a NULL into the column, shouldn't it take the DEFAULT value instead?
Please teach me how to get the DEFAULT values to be inserted instead.
What should I look out for?
Thank you.
The default value will be used for a column if a value is not supplied in the INSERT statement for this column.
So don't include the columns that you want to get their default values in the list like this:
INSERT INTO KTI.FKTIM04 (
ObjectID
)
VALUES (
'UMSTM0LW8A8Z50DT4WA7U93EEQDRXRTH'
)
this way the row will be inserted and the 2 columns, since they were not specified in the list, will get their default values.
See the demo.
Another way to achieve the same is by using DEFAULT keyword:
INSERT INTO FKTIM04 (
UP_Change_CL
,UP_ctrl_CL
,ObjectID
)
VALUES (
DEFAULT
,DEFAULT
,'UMSTM0LW8A8Z50DT4WA7U93EEQDRXRTH'
)
See the demo.

Possible to assign a default value on a NULL against table column in sql

I am wondering if there is a way that when creating a table that you can assign a default value to a column if the value is null.
I understand that you can use the syntax DEFAULT however this is only for when the value is absent. Is there a way similar to this that you can say when NULL it will add the default without using a trigger.
CREATE TABLE DBO.TESTS
(
TEST VARCHAR(100) DEFAULT(ISNULL('test',NULL)),
NUM INT
)
This is a test and the kind of thing i was looking at?
UPDATE:
Example input
INSERT INTO TESTS (TEST,NUM)
VALUES (NULL,1)
Where the "NULL" is i would like that to enter the value "test". But also if i was to do the following
INSERT INTO TESTS (NUM)
VALUES (1)
This would also enter the value of "test" into the column "TEST".
I hope this helps.
Yes, there is a way to do what you want. It is called a trigger. You would have to define a trigger that sets the value when a NULL is inserted into the column.
If you use an INSTEAD OF trigger, then you can still declare the column as NOT NULL. The trigger will take care of assigning a value so the constraint is not violated.
So, you can do this. Why you would want to do it is another question. Perhaps you are not familiar with the DEFAULT keyword that allows default values to be inserted using a VALUES() clause. This is explained in the documentation for INSERT.
You can add a default constraint to your table which will automatically add a set value for the column if the insert does not have a value for it:
CREATE TABLE DBO.TESTS
(
TEST VARCHAR(100),
NUM INT
)
ALTER TABLE [DBO].[TESTS] ADD CONSTRAINT [DF_TESTS_TEST] DEFAULT (N'default_value_goes_here') FOR [TEST]
INSERT INTO [DBO].[TESTS] VALUES (NULL, 1)
INSERT INTO [DBO].[TESTS] (num) VALUES (2)
Results
NULL 1
'default_value_goes_here' 2
If you want to check during an insert you can use COALESCE
DECLARE #insertValue VARCHAR(100)
SET #insertValue = NULL
INSERT INTO DBO.TESTS VALUES (COALESCE (#insertValue, 'defaultValue'), 1);
The bottom line is that the column should be non-nullable with a default value.
It's possible to replace null values with default values in a trigger for insert/update, but that doesn't make any sense - first because it means every update/insert will have to do that extra work, and second, because that would make it impossible to insert null to the column (unless the triggers are disabled) so why allow nulls in the first place? It's a mistake that will only be confusing for anyone attempting to use that table.
Think about it from the user side - when you send null to a nullable column, you expect it to be null, you don't expect it to contain a value.
If you run this insert statement:
INSERT INTO TESTS (TEST,NUM)
VALUES (NULL,1)
You expect the table to contain a row where Test is null and num = 1.
You do not expect the Test column to contain the default value.
When providing a value for a column, including NULL, that value will be used. NULL is still a value, just an unknown value. A DEFAULT value will only be used if no value is passed (which, as I just said, NULL is a value so doesn't count).
If you don't want a NULL in your table, then instead stop people supplying them by setting your column as NOT NULL:
CREATE TABLE dbo.TestTable (ID int, String varchar(100) NOT NULL DEFAULT 'test')
GO
--INSERT is successful, String has a value of 'test'
INSERT INTO dbo.TestTable (ID)
VALUES(1);
GO
--INSERT fails, String cannot have a value of NULL
INSERT INTO dbo.TestTable (ID,
String)
VALUES(2,NULL);
GO
SELECT *
FROM dbo.TestTable;
GO
DROP TABLE dbo.TestTable;
GO

NULL constraint after attribute in CREATE TABLE?

I'm new to SQL and I'm trying to figure out what this NULL is doing. Here a simple example:
CREATE TABLE test (
bla VARCHAR NULL
);
So I tried to figure out wether this is set to be the default value, but it is null as default wether I put it there or not, right?
Also I wondered if it has to stay null (for whatever reason) but when I tried to insert a value it was possible anyway. So does it do anything?
From CREATE TABLE:
NULL
The column is allowed to contain null values. This is the default.
You could write:
INSERT INTO test(bla)
VALUES (NULL);
-- it holds NULL
INSERT INTO test(bla)
VALUES (default);
-- it holds NULL
INSERT INTO test(bla)
VALUES ('a');
-- it holds 'a'
You could also omit column:
CREATE TABLE test2(bla VARCHAR NULL, col2 INT NOT NULL);
INSERT INTO test2(col2) VALUES (1);
-- it contains NULL, 1
If you specify column as:
CREATE TABLE test(bla VARCHAR NOT NULL);
INSERT INTO test(bla) VALUES (NULL);
-- error
EDIT:
You don't have to specify NULL explicitly.
CREATE TABLE test(bla VARCHAR);
is the same as:
CREATE TABLE test (bla VARCHAR NULL);
You are parameterizing the column can be NULL

sql not null property error

I have a sql table and here is my column which gives error. When I try to add a new record which has null active_status to this table, It gives "not-null property references a null or transient value" error. Is there any idea?
active_status character varying(30) NOT NULL DEFAULT 'NEW'::character varying,
EDIT: I have created a new simple table;
CREATE TABLE mytable
(
"MyData" character varying(30) NOT NULL DEFAULT 'NEW'::character varying,
CONSTRAINT mytable_pkey PRIMARY KEY ("MyData" )
)
WITH (
OIDS=FALSE
);
ALTER TABLE mytable
OWNER TO postgres;
When I try to insert a string, it runs fine;
insert into mytable values('ssss');
But when I try to insert a null value it gives error;
insert into mytable values(null);
ERROR: null value in column "MyData" violates not-null constraint
SQL state: 23502
With this statement:
insert into mytable values(null);
you explicitely requested to insert a NULL value into the column MyData and therefor you get the error message.
If you want to use the default value, you need to tell the DBMS to do so:
insert into mytable values (default);
Btw: it is much better coding style to always specify the columns in the insert statement:
insert into mytable ("MyData") values (null);
And another thing: you should avoid using quoted identifiers ("MyData" vs. MyData) , they simply are more trouble than it's worth it.
You need to first create the column with NULL constraint. Update all rows for that column with the default values. Alter the column to have Not Null constraint

Either OR non-null constraints in MySQL

What's the best way to create a non-NULL constraint in MySQL such that fieldA and fieldB can't both be NULL. I don't care if either one is NULL by itself, just as long as the other field has a non-NULL value. And if they both have non-NULL values, then it's even better.
This isn't an answer directly to your question, but some additional information.
When dealing with multiple columns and checking if all are null or one is not null, I typically use COALESCE() - it's brief, readable and easily maintainable if the list grows:
COALESCE(a, b, c, d) IS NULL -- True if all are NULL
COALESCE(a, b, c, d) IS NOT NULL -- True if any one is not null
This can be used in your trigger.
#Sklivvz: Testing with MySQL 5.0.51a, I find it parses a CHECK constraint, but does not enforce it. I can insert (NULL, NULL) with no error. Tested both MyISAM and InnoDB. Subsequently using SHOW CREATE TABLE shows that a CHECK constraint is not in the table definition, even though no error was given when I defined the table.
This matches the MySQL manual which says: "The CHECK clause is parsed but ignored by all storage engines."
So for MySQL, you would have to use a trigger to enforce this rule. The only problem is that MySQL triggers have no way of raising an error or aborting an INSERT operation. One thing you can do in the trigger to cause an error is to set a NOT NULL column to NULL.
CREATE TABLE foo (
FieldA INT,
FieldB INT,
FieldA_or_FieldB TINYINT NOT NULL;
);
DELIMITER //
CREATE TRIGGER FieldABNotNull BEFORE INSERT ON foo
FOR EACH ROW BEGIN
IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
SET NEW.FieldA_or_FieldB = NULL;
ELSE
SET NEW.FieldA_or_FieldB = 1;
END IF;
END//
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, 10); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (10, NULL); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, NULL); -- gives error
You also need a similar trigger BEFORE UPDATE.
MySQL 5.5 introduced SIGNAL, so we don't need the extra column in Bill Karwin's answer any more. Bill pointed out you also need a trigger for update so I've included that too.
CREATE TABLE foo (
FieldA INT,
FieldB INT
);
DELIMITER //
CREATE TRIGGER InsertFieldABNotNull BEFORE INSERT ON foo
FOR EACH ROW BEGIN
IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '\'FieldA\' and \'FieldB\' cannot both be null';
END IF;
END//
CREATE TRIGGER UpdateFieldABNotNull BEFORE UPDATE ON foo
FOR EACH ROW BEGIN
IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '\'FieldA\' and \'FieldB\' cannot both be null';
END IF;
END//
DELIMITER ;
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, 10); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (10, NULL); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, NULL); -- gives error
UPDATE foo SET FieldA = NULL; -- gives error
This is the standard syntax for such a constraint, but MySQL blissfully ignores the constraint afterwards
ALTER TABLE `generic`
ADD CONSTRAINT myConstraint
CHECK (
`FieldA` IS NOT NULL OR
`FieldB` IS NOT NULL
)
I've done something similar in SQL Server, I'm not sure if it will work directly in MySQL, but:
ALTER TABLE tableName ADD CONSTRAINT constraintName CHECK ( (fieldA IS NOT NULL) OR (fieldB IS NOT NULL) );
At least I believe that's the syntax.
However, keep in mind that you cannot create check constraints across tables, you can only check the columns within one table.
I accomplished this using a GENERATED ALWAYS column with COALESCE ... NOT NULL:
DROP TABLE IF EXISTS `error`;
CREATE TABLE IF NOT EXISTS `error` (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
left_id BIGINT UNSIGNED NULL,
right_id BIGINT UNSIGNED NULL,
left_or_right_id BIGINT UNSIGNED GENERATED ALWAYS AS (COALESCE(left_id, right_id)) NOT NULL,
when_occurred TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
message_text LONGTEXT NOT NULL,
INDEX id_index (id),
INDEX when_occurred_index (when_occurred),
INDEX left_id_index (left_id),
INDEX right_id_index (right_id)
);
INSERT INTO `error` (left_id, right_id, message_text) VALUES (1, 1, 'Some random text.'); -- Ok.
INSERT INTO `error` (left_id, right_id, message_text) VALUES (null, 1, 'Some random text.'); -- Ok.
INSERT INTO `error` (left_id, right_id, message_text) VALUES (1, null, 'Some random text.'); -- Ok.
INSERT INTO `error` (left_id, right_id, message_text) VALUES (null, null, 'Some random text.'); -- ER_BAD_NULL_ERROR: Column 'left_or_right_id' cannot be null
on MySQL version 8.0.22