Constraint on values, oracle database - sql

I would like to have a table in my Oracle database where the values of an attribute1 (values may change) can't be greater than the value (fixed) of attribute2.
Is it possible to enforce such a rule?
Is it possible to make a value impossible to change after the insert ?

Disallowing attribute1 from being larger than attribute2 can be done with a check constraint:
ALTER TABLE mytable
ADD CONSTRAINT attribute2_greater_check
CHECK (attribute2 >= attribute1)
Preventing update of attribute2 can be done with a trigger that raises an error:
CREATE OR REPLACE TRIGGER mytable_attribute2_update_tr
BEFORE UPDATE ON mytable
FOR EACH ROW
BEGIN
IF :NEW.attribute2 != :OLD.attribute2
THEN
RAISE_APPLICATION_ERROR(-20101, 'attribute2 cannot be updated');
END IF;
END;
/

One way to do is to use an appropriate CONSTRAINT when creating the table:
CREATE TABLE table_name
(
column1 integer,
column2 integer not null,
CONSTRAINT constraint_name CHECK (column1 <= column2)
);
INSERT INTO table_name VALUES(1,1); //ok
INSERT INTO table_name VALUES(2,1); //gives an error
Such constraints can use any fields in the table at hand, but may not access other tables via a subselect.
EDIT: I just realized you also asked another question ... that has been answered already by #Mureinik.

Related

Missing Keyword Error in Oracle SQL Database [duplicate]

I was wondering how can I add an identity column to existing oracle table? I am using oracle 11g. Suppose I have a table named DEGREE and I am going to add an identity column to that.
FYI table is not empty.
You can not do it in one step. Instead,
Alter the table and add the column (without primary key constraint)
ALTER TABLE DEGREE ADD (Ident NUMBER(10));
Fill the new column with data which will fulfill the primary key constraint (unique/not null), e.g. like
UPDATE DEGREE SET Ident=ROWNUM;
Alter the table and add the constraint to the column
ALTER TABLE DEGREE MODIFY (Ident PRIMARY KEY);
After that is done, you can set up a SEQUENCE and a BEFORE INSERT trigger to automatically set the id value for new records.
From Oracle 12c you would use an identity column.
For example, say your table is called demo and has 3 columns and 100 rows:
create table demo (col1, col2, col3)
as
select dbms_random.value(1,10), dbms_random.value(1,10), dbms_random.value(1,10)
from dual connect by rownum <= 100;
You could add an identity column using:
alter table demo add demo_id integer generated by default on null as identity;
update demo set demo_id = rownum;
Then reset the internal sequence to match the data and prevent manual inserts:
alter table demo modify demo_id generated always as identity start with limit value;
and define it as the primary key:
alter table demo add constraint demo_pk primary key (demo_id);
This leaves the new column at the end of the column list, which shouldn’t normally matter (except for tables with a large number of columns and row chaining issues), but it looks odd when you describe the table. However, we can at least tidy up the dictionary order using the invisible/visible hack:
SQL> desc demo
Name Null? Type
-------------------------------- -------- ----------------------
COL1 NUMBER
COL2 NUMBER
COL3 NUMBER
DEMO_ID NOT NULL NUMBER(38)
begin
for r in (
select column_name from user_tab_columns c
where c.table_name = 'DEMO'
and c.column_name <> 'DEMO_ID'
order by c.column_id
)
loop
execute immediate 'alter table demo modify '||r.column_name||' invisible';
execute immediate 'alter table demo modify '||r.column_name||' visible';
end loop;
end;
/
SQL> desc demo
Name Null? Type
-------------------------------- -------- ----------------------
DEMO_ID NOT NULL NUMBER(38)
COL1 NUMBER
COL2 NUMBER
COL3 NUMBER
One thing you can't do (as of Oracle 18.0) is alter an existing column to make it into an identity column, so you have to either go through a process like the one above but copying the existing values and finally dropping the old column, or else define a new table explicitly with the identity column in place and copy the data across in a separate step. Otherwise you'll get:
-- DEMO_ID column exists but is currently not an identity column:
alter table demo modify demo_id generated by default on null as identity start with limit value;
-- Fails with:
ORA-30673: column to be modified is not an identity column
add the column
alter table table_name add (id INTEGER);
create a sequence table_name_id_seq with start with clause, using number of rows in the table + 1 or another safe value(we don't want duplicate ids);
lock the table (no inserts)
alter table table_name lock exclusive mode;
fill the column
update table_name set id = rownum; --or another logic
add a trigger to automaticaly put the id on insert using the sequence(you can find examples on internet, for example this answer)
When you'll fire the create trigger the lock will be released. (it automatically commits).
Also, you may add unique constraint on the id column, it is best to do so.
For Oracle :
CREATE TABLE new_table AS (SELECT ROWNUM AS id, ta.* FROM old_table ta)
remember this id column is not auto incremented

PostgreSQL constraint using prefixes

Let's say I have the following PostgreSQL table:
id | key
---+--------
1 | 'a.b.c'
I need to prevent inserting records with a key that is a prefix of another key. For example, I should be able to insert:
'a.b.b'
But the following keys should not be accepted:
'a.b'
'a.b.c'
'a.b.c.d'
Is there a way to achieve this - either by a constraint or by a locking mechanism (check the existance before inserting)?
This solution is based on PostgreSQL user-defined operators and exclusion constraints (base syntax, more details).
NOTE: more testing shows this solution does not work (yet). See bottom.
Create a function has_common_prefix(text,text) which will calculate logically what you need. Mark the function as IMMUTABLE.
CREATE OR REPLACE FUNCTION
has_common_prefix(text,text)
RETURNS boolean
IMMUTABLE STRICT
LANGUAGE SQL AS $$
SELECT position ($1 in $2) = 1 OR position ($2 in $1) = 1
$$;
Create an operator for the index
CREATE OPERATOR <~> (
PROCEDURE = has_common_prefix,
LEFTARG = text,
RIGHTARG = text,
COMMUTATOR = <~>
);
Create exclusion constraint
CREATE TABLE keys ( key text );
ALTER TABLE keys
ADD CONSTRAINT keys_cannot_have_common_prefix
EXCLUDE ( key WITH <~> );
However, the last point produces this error:
ERROR: operator <~>(text,text) is not a member of operator family "text_ops"
DETAIL: The exclusion operator must be related to the index operator class for the constraint.
This is because to create an index PostgreSQL needs logical operators to be bound with physical indexing methods, via entities calles "operator classes". So we need to provide that logic:
CREATE OR REPLACE FUNCTION keycmp(text,text)
RETURNS integer IMMUTABLE STRICT
LANGUAGE SQL AS $$
SELECT CASE
WHEN $1 = $2 OR position ($1 in $2) = 1 OR position ($2 in $1) = 1 THEN 0
WHEN $1 < $2 THEN -1
ELSE 1
END
$$;
CREATE OPERATOR CLASS key_ops FOR TYPE text USING btree AS
OPERATOR 3 <~> (text, text),
FUNCTION 1 keycmp (text, text)
;
ALTER TABLE keys
ADD CONSTRAINT keys_cannot_have_common_prefix
EXCLUDE ( key key_ops WITH <~> );
Now, it works:
INSERT INTO keys SELECT 'ara';
INSERT 0 1
INSERT INTO keys SELECT 'arka';
INSERT 0 1
INSERT INTO keys SELECT 'barka';
INSERT 0 1
INSERT INTO keys SELECT 'arak';
psql:test.sql:44: ERROR: conflicting key value violates exclusion constraint "keys_cannot_have_common_prefix"
DETAIL: Key (key)=(arak) conflicts with existing key (key)=(ara).
INSERT INTO keys SELECT 'bark';
psql:test.sql:45: ERROR: conflicting key value violates exclusion constraint "keys_cannot_have_common_prefix"
DETAIL: Key (key)=(bark) conflicts with existing key (key)=(barka).
NOTE: more testing shows this solution does not work yet: The last INSERT should fail.
INSERT INTO keys SELECT 'a';
INSERT 0 1
INSERT INTO keys SELECT 'ac';
ERROR: conflicting key value violates exclusion constraint "keys_cannot_have_common_prefix"
DETAIL: Key (key)=(ac) conflicts with existing key (key)=(a).
INSERT INTO keys SELECT 'ab';
INSERT 0 1
You can use ltree module to achieve this, it will let you to create hierarchical tree-like structures. Also will help you to prevent from reinventing the wheel, creating complicated regular expressions and so on. You just need to have postgresql-contrib package installed. Take a look:
--Enabling extension
CREATE EXTENSION ltree;
--Creating our test table with a pre-loaded data
CREATE TABLE test_keys AS
SELECT
1 AS id,
'a.b.c'::ltree AS key_path;
--Now we'll do the trick with a before trigger
CREATE FUNCTION validate_key_path() RETURNS trigger AS $$
BEGIN
--This query will do our validation.
--It'll search if a key already exists in 'both' directions
--LIMIT 1 because one match is enough for our validation :)
PERFORM * FROM test_keys WHERE key_path #> NEW.key_path OR key_path <# NEW.key_path LIMIT 1;
--If found a match then raise a error
IF FOUND THEN
RAISE 'Duplicate key detected: %', NEW.key_path USING ERRCODE = 'unique_violation';
END IF;
--Great! Our new row is able to be inserted
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER test_keys_validator BEFORE INSERT OR UPDATE ON test_keys
FOR EACH ROW EXECUTE PROCEDURE validate_key_path();
--Creating a index to speed up our validation...
CREATE INDEX idx_test_keys_key_path ON test_keys USING GIST (key_path);
--The command below will work
INSERT INTO test_keys VALUES (2, 'a.b.b');
--And the commands below will fail
INSERT INTO test_keys VALUES (3, 'a.b');
INSERT INTO test_keys VALUES (4, 'a.b.c');
INSERT INTO test_keys VALUES (5, 'a.b.c.d');
Of course I did not bother creating primary key and other constraints for this test. But do not forget to do so. Also, there is much more on ltree module than I'm showing, if you need something different take a look on its docs, perhaps you'll find the answer there.
You can try below trigger. Please note that key is sql reserve word. So I would suggest you avoid using that as column name in your table.
I have added my create table syntax also for testing purpose:
CREATE TABLE my_table
(myid INTEGER, mykey VARCHAR(50));
CREATE FUNCTION check_key_prefix() RETURNS TRIGGER AS $check_key_prefix$
DECLARE
v_match_keys INTEGER;
BEGIN
v_match_keys = 0;
SELECT COUNT(t.mykey) INTO v_match_keys
FROM my_table t
WHERE t.mykey LIKE CONCAT(NEW.mykey, '%')
OR NEW.mykey LIKE CONCAT(t.mykey, '%');
IF v_match_keys > 0 THEN
RAISE EXCEPTION 'Prefix Key Error occured.';
END IF;
RETURN NEW;
END;
$check_key_prefix$ LANGUAGE plpgsql;
CREATE TRIGGER check_key_prefix
BEFORE INSERT OR UPDATE ON my_table
FOR EACH ROW
EXECUTE PROCEDURE check_key_prefix();
Here is a CHECK - based solution - it may satisfy your needs.
CREATE TABLE keys ( id serial primary key, key text );
CREATE OR REPLACE FUNCTION key_check(text)
RETURNS boolean
STABLE STRICT
LANGUAGE SQL AS $$
SELECT NOT EXISTS (
SELECT 1 FROM keys
WHERE key ~ ( '^' || $1 )
OR $1 ~ ( '^' || key )
);
$$;
ALTER TABLE keys
ADD CONSTRAINT keys_cannot_have_common_prefix
CHECK ( key_check(key) );
PS. Unfortunately, it fails in one point (multi - row inserts).
SQL is a very powerful language. Usually you can do most of the things by plain select statements. I.e. if you do not like triggers, you can use a this method for your inserts.
The only assumption is there exists at least 1 row in the table. (*)
The table:
create table my_table
(
id integer primary key,
key varchar(100)
);
Because of the assumption, we'll have at least 1 row.(*)
insert into my_table (id, key) values (1, 'a.b.c');
Now the magic sql. The trick is replace the p_key value by your key value to insert. I have, intentionally, not put that statement into a stored procedure. Because I want it to be straight forward if you want to carry it to your application side. But usually putting sql into stored procedure is better.
insert into my_table (id, key)
select (select max(id) + 1 from my_table), p_key
from my_table
where not exists (select 'p' from my_table where key like p_key || '%' or p_key like key || '%')
limit 1;
Now the tests:
-- 'a.b.b' => Inserts
insert into my_table (id, key)
select (select max(id) + 1 from my_table), 'a.b.b'
from my_table
where not exists (select 'p' from my_table where key like 'a.b.b' || '%' or 'a.b.b' like key || '%')
limit 1;
-- 'a.b' => does not insert
insert into my_table (id, key)
select (select max(id) + 1 from my_table), 'a.b'
from my_table
where not exists (select 'p' from my_table where key like 'a.b' || '%' or 'a.b' like key || '%')
limit 1;
-- 'a.b.c' => does not insert
insert into my_table (id, key)
select (select max(id) + 1 from my_table), 'a.b.c'
from my_table
where not exists (select 'p' from my_table where key like 'a.b.c' || '%' or 'a.b.c' like key || '%')
limit 1;
-- 'a.b.c.d' does not insert
insert into my_table (id, key)
select (select max(id) + 1 from my_table), 'a.b.c.d'
from my_table
where not exists (select 'p' from my_table where key like 'a.b.c.d' || '%' or 'a.b.c.d' like key || '%')
limit 1;
(*) If you wish you can get rid of this existence of the single row by introducing an Oracle like dual table. If you wish modifying the insert statement is straight forward. Let me know if you wish to do so.
One possible solution is to create a secondary table that holds the prefixes of your keys, and then use a combination of unique and exclusion constraints with an insert trigger to enforce the uniqueness semantics you want.
At a high level, this approach breaks each key down into a list of prefixes and applies something similar to readers-writer lock semantics: any number of keys may share a prefix as long as none of the keys equals the prefix. To accomplish that, the list of prefixes includes the key itself with a flag that marks it as a terminal prefix.
The secondary table looks like this. We use a CHAR rather than a BOOLEAN for the flag because later on we’ll be adding a constraint that doesn’t work on boolean columns.
CREATE TABLE prefixes (
id INTEGER NOT NULL,
prefix TEXT NOT NULL,
is_terminal CHAR NOT NULL,
CONSTRAINT prefixes_id_fk
FOREIGN KEY (id)
REFERENCES your_table (id)
ON DELETE CASCADE,
CONSTRAINT prefixes_is_terminal
CHECK (is_terminal IN ('t', 'f'))
);
Now we’ll need to define a trigger on insert into your_table to also insert rows into prefixes, such that
INSERT INTO your_table (id, key) VALUES (1, ‘abc');
causes
INSERT INTO prefixes (id, prefix, is_terminal) VALUES (1, 'a', ‘f’);
INSERT INTO prefixes (id, prefix, is_terminal) VALUES (1, 'ab', ‘f’);
INSERT INTO prefixes (id, prefix, is_terminal) VALUES (1, 'abc', ’t’);
The trigger function might look like this. I’m only covering the INSERT case here, but the function could be made to handle UPDATE as well by deleting the old prefixes and then inserting the new ones. The DELETE case is covered by the cascading foreign-key constraint on prefixes.
CREATE OR REPLACE FUNCTION insert_prefixes() RETURNS TRIGGER AS $$
DECLARE
is_terminal CHAR := 't';
remaining_text TEXT := NEW.key;
BEGIN
LOOP
IF LENGTH(remaining_text) <= 0 THEN
EXIT;
END IF;
INSERT INTO prefixes (id, prefix, is_terminal)
VALUES (NEW.id, remaining_text, is_terminal);
is_terminal := 'f';
remaining_text := LEFT(remaining_text, -1);
END LOOP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
We add this function to the table as a trigger in the usual way.
CREATE TRIGGER insert_prefixes
AFTER INSERT ON your_table
FOR EACH ROW
EXECUTE PROCEDURE insert_prefixes();
An exclusion constraint and a partial unique index will enforce that a row where is_terminal = ’t’ can't collide with another row of the same prefix regardless of its is_terminal value, and that there's only one row with is_terminal = ’t’:
ALTER TABLE prefixes ADD CONSTRAINT prefixes_forbid_conflicts
EXCLUDE USING gist (prefix WITH =, is_terminal WITH <>);
CREATE UNIQUE INDEX ON prefixes (prefix) WHERE is_terminal = 't';
This allows new rows that don’t conflict but prevents ones that do conflict, including in multi-row INSERTs.
db=# INSERT INTO your_table (id, key) VALUES (1, 'a.b.c');
INSERT 0 1
db=# INSERT INTO your_table (id, key) VALUES (2, 'a.b.b');
INSERT 0 1
db=# INSERT INTO your_table (id, key) VALUES (3, 'a.b');
ERROR: conflicting key value violates exclusion constraint "prefixes_forbid_conflicts"
db=# INSERT INTO your_table (id, key) VALUES (4, 'a.b.c');
ERROR: duplicate key value violates unique constraint "prefixes_prefix_idx"
db=# INSERT INTO your_table (id, key) VALUES (5, 'a.b.c.d');
ERROR: conflicting key value violates exclusion constraint "prefixes_forbid_conflicts"
db=# INSERT INTO your_table (id, key) VALUES (6, 'a.b.d'), (7, 'a');
ERROR: conflicting key value violates exclusion constraint "prefixes_forbid_conflicts"

Multiple constraints in table: How to get all violations?

I have a table in Oracle with several constraints. When I insert a new record and not all constraints are valid, then Oracle raise only the "first" error. How to get all violations of my record?
CREATE TABLE A_TABLE_TEST (
COL_1 NUMBER NOT NULL,
COL_2 NUMBER NOT NULL,
COL_3 NUMBER NOT NULL,
COL_4 NUMBER NOT NULL
);
INSERT INTO A_TABLE_TEST values (1,null,null,2);
ORA-01400: cannot insert NULL into ("USER_4_8483C"."A_TABLE_TEST"."COL_2")
I would like to get something like this:
Column COL_2: cannot insert NULL
Column COL_3: cannot insert NULL
This would be also sufficient:
Column COL_2: not valid
Column COL_3: not valid
Of course I could write a trigger and check each column individually, but I like to prefer constraints rather than triggers, they are easier to maintain and don't require manually written code.
Any idea?
There no straightforward way to report all possible constraint violations. Because when Oracle stumble on first violation of a constraint, no further evaluation is possible, statement fails, unless that constraint is deferred one or the log errors clause has been included in the DML statement. But it should be noted that log errors clause won't be able to catch all possible constraint violations, just records first one.
As one of the possible ways is to:
create exceptions table. It can be done by executing ora_home/rdbms/admin/utlexpt.sql script. The table's structure is pretty simple;
disable all table constraints;
execute DMLs;
enable all constraints with exceptions into <<exception table name>> clause. If you executed utlexpt.sql script, the name of the table exceptions are going to be stored would be exceptions.
Test table:
create table t1(
col1 number not null,
col2 number not null,
col3 number not null,
col4 number not null
);
Try to execute an insert statement:
insert into t1(col1, col2, col3, col4)
values(1, null, 2, null);
Error report -
SQL Error: ORA-01400: cannot insert NULL into ("HR"."T1"."COL2")
Disable all table's constraints:
alter table T1 disable constraint SYS_C009951;
alter table T1 disable constraint SYS_C009950;
alter table T1 disable constraint SYS_C009953;
alter table T1 disable constraint SYS_C009952;
Try to execute the previously failed insert statement again:
insert into t1(col1, col2, col3, col4)
values(1, null, 2, null);
1 rows inserted.
commit;
Now, enable table's constraints and store exceptions, if there are any, in the exceptions table:
alter table T1 enable constraint SYS_C009951 exceptions into exceptions;
alter table T1 enable constraint SYS_C009950 exceptions into exceptions;
alter table T1 enable constraint SYS_C009953 exceptions into exceptions;
alter table T1 enable constraint SYS_C009952 exceptions into exceptions;
Check the exceptions table:
column row_id format a30;
column owner format a7;
column table_name format a10;
column constraint format a12;
select *
from exceptions
ROW_ID OWNER TABLE_NAME CONSTRAINT
------------------------------ ------- ------- ------------
AAAWmUAAJAAAF6WAAA HR T1 SYS_C009951
AAAWmUAAJAAAF6WAAA HR T1 SYS_C009953
Two constraints have been violated. To find out column names, simply refer to user_cons_columns data dictionary view:
column table_name format a10;
column column_name format a7;
column row_id format a20;
select e.table_name
, t.COLUMN_NAME
, e.ROW_ID
from user_cons_columns t
join exceptions e
on (e.constraint = t.constraint_name)
TABLE_NAME COLUMN_NAME ROW_ID
---------- ---------- --------------------
T1 COL2 AAAWmUAAJAAAF6WAAA
T1 COL4 AAAWmUAAJAAAF6WAAA
The above query gives us column names, and rowids of problematic records. Having rowids at hand, there should be no problem to find those records that cause constraint violation, fix them, and re-enable constraints once again.
Here is the script that has been used to generate alter table statements for enabling and disabling constraints:
column cons_disable format a50
column cons_enable format a72
select 'alter table ' || t.table_name || ' disable constraint '||
t.constraint_name || ';' as cons_disable
, 'alter table ' || t.table_name || ' enable constraint '||
t.constraint_name || ' exceptions into exceptions;' as cons_enable
from user_constraints t
where t.table_name = 'T1'
order by t.constraint_type
You would have to implement a before-insert trigger to loop through all the conditions that you care about.
Think about the situation from the database's perspective. When you do an insert, the database can basically do two things: complete the insert successfully or fail for some reason (typically a constraint violation).
The database wants to proceed as quickly as possibly and not do unnecessary work. Once it has found the first complaint violation, it knows that the record is not going into the database. So, the engine wisely returns an error and stops checking further constraints. There is no reason for the engine to get the full list of violations.
In the meantime I found a lean solution using deferred constraints:
CREATE TABLE A_TABLE_TEST (
COL_1 NUMBER NOT NULL DEFERRABLE INITIALLY DEFERRED,
COL_2 NUMBER NOT NULL DEFERRABLE INITIALLY DEFERRED,
COL_3 NUMBER NOT NULL DEFERRABLE INITIALLY DEFERRED,
COL_4 NUMBER NOT NULL DEFERRABLE INITIALLY DEFERRED
);
INSERT INTO A_TABLE_TEST values (1,null,null,2);
DECLARE
CHECK_CONSTRAINT_VIOLATED EXCEPTION;
PRAGMA EXCEPTION_INIT(CHECK_CONSTRAINT_VIOLATED, -2290);
REF_CONSTRAINT_VIOLATED EXCEPTION;
PRAGMA EXCEPTION_INIT(REF_CONSTRAINT_VIOLATED , -2292);
CURSOR CheckConstraints IS
SELECT TABLE_NAME, CONSTRAINT_NAME, COLUMN_NAME
FROM USER_CONSTRAINTS
JOIN USER_CONS_COLUMNS USING (TABLE_NAME, CONSTRAINT_NAME)
WHERE TABLE_NAME = 'A_TABLE_TEST'
AND DEFERRED = 'DEFERRED'
AND STATUS = 'ENABLED';
BEGIN
FOR aCon IN CheckConstraints LOOP
BEGIN
EXECUTE IMMEDIATE 'SET CONSTRAINT '||aCon.CONSTRAINT_NAME||' IMMEDIATE';
EXCEPTION
WHEN CHECK_CONSTRAINT_VIOLATED OR REF_CONSTRAINT_VIOLATED THEN
DBMS_OUTPUT.PUT_LINE('Constraint '||aCon.CONSTRAINT_NAME||' at Column '||aCon.COLUMN_NAME||' violated');
END;
END LOOP;
END;
It works with any check constraint (not only NOT NULL). Checking FOREIGN KEY Constraint should work as well.
Add/Modify/Delete of constraints does not require any further maintenance.

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

Update value on insert into table in SQL Server

I am working with SQL Server - on inserting into a table, I have a unique constraint on a table column id. There is a possibility that when inserting, the value going into the id column is 0. This will cause an error.
Is it possible to update this id to another value during the insert if the id value is 0? This is to prevent the error and to give it a valid value.
Possibly a trigger?
A trigger is one way, but you may want to use a filtered index (CREATE UNIQUE INDEX, not as a table constraint) to ignore zero value. This way, you don't have to worry about what value to put there
Alternatively, if you want to populate it from another column, you can have a computed column with a unique constraint.
ALTER TABLE whatever
ADD ComputedUniqueCol = CASE WHEN Id = 0 THEN OtherCol ELSE Id END
If that's your primary key you can specify it as IDENTITY. Then it should generate a value for itself based on seed and increment (the default is seed=1 and default=1) so you don't have to worry about it.
CREATE TABLE MyTable
(
ID int PRIMARY KEY IDENTITY,
...
)
create an "instead of" trigger and check for the value on the ID.
CREATE trigger checkID
on YOUR_TABLE
instead of insert
as
begin
declare #id int
select #id=id from inserted
if (#id==0) begin
--DO YOUR LOGIC HERE AND THEN INSERT
end else begin
insert into DESTINATION_TABLE (VALUES)
SELECT VALUES FROM INSERTED
end
end