Null values found - sql

I want to insert a not null value. This is a example:
create table time(
a varchar2(9),
b varchar2(9),
c varchar2(9));
table create
insert into time (a,c) values ('qq','ee');
table altered
When I key this:
alter table time
modify b varchar2(9) not null;
This error come out:
alter table time
*
ERROR at line 1:
ORA-02296: cannot enable (DIP0114713.) - null values found
So how I insert a value to a and c column and also column b is not null?

If you don't mention a column in an insert, then it gets the default value. By default, the default value is NULL. You can specify something else:
create table time (
a varchar2(9),
b varchar2(9) not null default 'NO VALUE',
c varchar2(9))
);
EDIT:
To get your alter table to work, update the value first:
update time
set b = 'NO VALUE'
where b is null;

It's not possible.
First you need to update the data in column b and then apply not null constraint.
Update time set b= 'NA' where b is null
go
ALTER TABLE time
ALTER COLUMN b varchar(9) NOT NULL
go

It is possible to create a constraint without it impacting existing rows:
create table test1(
a varchar2(9),
b varchar2(9),
c varchar2(9));
insert into test1 (a,c) values ('qq','ee');
commit;
alter table test1 modify b varchar2(9) not null novalidate;
select * from test1;
A B C
--------- --------- ---------
qq ee
insert into test1 (a,c) values ('qq2','ee2');
ORA-01400: cannot insert NULL into ("SCHEMA1"."TEST1"."B")
However, I would NOT recommend using this, as if you need to create future constraints on the table, it could massively complicate things, since you have "invalid" data in the table.
Far better to take the hit and "fix" the data at the point when you're creating a constraint, rather than shrug your shoulders and leave it for another time - it will come back to bite you (or if not you, some other poor soul who's stuck maintaining the database in the future!) on the bum.

Related

How to avoid space(s) while inserting data in a table in oracle

I want to avoid leading and trailing spaces in a column of a table. I tried using below check constraints but showing error - "invalid relational operator".
alter table employee add (CONSTRAINT trm_name check(trim(name)));
alter table employee add (CONSTRAINT trm_name check(trim(dept)));
Suppose, I have a table employee, and want no leading and trailing spaces on both columns(name and dept). Could anyone please help me.
Regards,
Tarak
You can use a trigger:
CREATE OR REPLACE TRIGGER EMPLOYEE_BIU
BEFORE INSERT OR UPDATE ON EMPLOYEE
FOR EACH ROW
BEGIN
:NEW.DEPT := TRIM(:NEW.DEPT);
END EMPLOYEE_BIU;
I assume, in particular, you don't want to allow non-empty strings made up entirely of spaces in those columns.
If so, I would write the constraints with decode, which handles NULL the way needed for constraints (in which an equality like NULL=something is treated the same as TRUE - unlike the same equality in WHERE clauses or join conditions, where it is treated the same as FALSE).
For example:
alter table employee
add (CONSTRAINT trm_name check(decode(name, trim(name), 1, 0) = 1));
decode returns 1 if and only if name is NULL or name is non-NULL and it has no leading or trailing spaces. It returns 0 in all other cases - if name is all spaces, then trim(name) is NULL, name is not NULL, so decode returns 0 and the constraint is FALSE.
Note that often we write conditions in the form decode(a, b, 1) = 1 (the default return value of decode is NULL, so this suffices in WHERE clauses and in join conditions). In constraints, NULL = 1 is handled the same as TRUE, so this shorthand will not work; we must give a non-NULL value in decode when a and b are not the same.
You can use the CHECK constraint as follows:
SQL> CREATE TABLE ABC (
2 NAME VARCHAR2(100) CHECK ( NAME = TRIM(NAME) ), -- use CHECK constraint
3 DEPT VARCHAR2(100) CHECK ( DEPT = TRIM(DEPT) ) -- use CHECK constraint
4 );
Table created.
SQL> -- space in name
SQL> INSERT INTO ABC VALUES (' TEJASH ','SO');
INSERT INTO ABC VALUES (' TEJASH ','SO')
*
ERROR at line 1:
ORA-02290: check constraint (TEJASH.SYS_C0014819) violated
SQL> -- space in department
SQL> INSERT INTO ABC VALUES ('TEJASH1',' SO');
INSERT INTO ABC VALUES ('TEJASH1',' SO')
*
ERROR at line 1:
ORA-02290: check constraint (TEJASH.SYS_C0014820) violated
SQL> -- valid record
SQL> INSERT INTO ABC VALUES ('TEJASH1','SO');
1 row created.
SQL>

Is there any way to reference column with different datatype?

I have 2 schemas/tables as shown:
CREATE TABLE schema1.code_tbl
( code CHAR(6) PRIMARY KEY,
description CHAR(30)
);
CREATE TABLE schema2.record_tbl
( rec_id VARCHAR(10) PRIMARY KEY,
curr_code VARCHAR(6),
remarks VARCHAR(30)
);
I need to create a foreign key reference from curr_code in RECORD_TBL to code in CODE_TBL.
ALTER TABLE schema2.record_tbl
ADD CONSTRAINT record_code_fk
FOREIGN KEY (curr_code)
REFERENCES schema1.code_tbl (code);
This obviously gives me an ORA-02267 (column type incompatible with referenced column) error.
I cannot alter the code column in CODE_TBL because I do not own or control schema1. I cannot alter the curr_code column in RECORD_TBL because it would break many functions in my application because we don't account for trailing whitespaces.
Is there any other way to enforce referential integrity between the 2 columns?
If schema2 is on Oracle 11g and above, using virtual column may solve your problem, but that will change the structure of your table which you are trying to avoid. If you can manage it, here is how it can be done
SQL> CREATE TABLE code_tbl
2 ( code CHAR(6) PRIMARY KEY,
3 description CHAR(30)
4 );
Table created
SQL>
SQL> CREATE TABLE record_tbl
2 ( rec_id VARCHAR2(10) PRIMARY KEY,
3 curr_code VARCHAR2(6),
4 remarks VARCHAR2(30)
5 );
Table created
SQL> INSERT INTO code_tbl(code, description) VALUES ('ABC', 'Test Data');
1 row inserted
SQL> INSERT INTO record_tbl(rec_id, curr_code, remarks) VALUES ('1', 'ABC', 'Test Row');
1 row inserted
SQL> SELECT * FROM record_tbl;
REC_ID CURR_CODE REMARKS
---------- --------- ------------------------------
1 ABC Test Row
SQL> SELECT * FROM code_tbl;
CODE DESCRIPTION
------ ------------------------------
ABC Test Data
SQL> ALTER TABLE record_tbl ADD curr_code_v CHAR(6) AS (trim(curr_code));
Table altered
SQL> SELECT * FROM record_tbl;
REC_ID CURR_CODE REMARKS CURR_CODE_V
---------- --------- ------------------------------ -----------
1 ABC Test Row ABC
SQL>
SQL> ALTER TABLE record_tbl
2 ADD CONSTRAINT record_code_fk
3 FOREIGN KEY (curr_code_v)
4 REFERENCES code_tbl (CODE);
Table altered
SQL> INSERT INTO record_tbl(rec_id, curr_code, remarks) VALUES ('2', 'ABC', 'Test Row 2');
1 row inserted
SQL> INSERT INTO record_tbl(rec_id, curr_code, remarks) VALUES ('3', 'XYZ', 'Test Row 2');
INSERT INTO record_tbl(rec_id, curr_code, remarks) VALUES ('3', 'XYZ', 'Test Row 2')
ORA-02291: integrity constraint (USER_X.RECORD_CODE_FK) violated - parent key not found
Here are the words from Tom Kyte regarding virtual columns:
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:676611400346196844
So the situation is this. You have an existing table record_tbl which is well established ( obviously, because changing it "break many functions"). Belatedly somebody has decided to enforce relational integrity on this table but has chosen to do so referencing a table in a different schema with a column of a different datatype.
Hmmmm.
Your options are:
Do nothing. Always an option; your application has survived with the current state for some length of time, maybe you can continue to live with the accrued technical debt.
Refactor one of the schemas. If you need to enforce the foreign key - and let's face it, relational integrity is a good thing - then you are going to have to change the datatype of one of the columns. Which one you choose is a project decision: changing a column in a schema you don't own is a political problem (initially), and political problems are usually harder than technical problems. Refactoring a schema by changing a column type is a matter of testing, testing, testing.
Replication. Build a materialized view in schema2 which copies the data from schema1.code_tbl. Crucially, define the MView code column match the datatype of schema2.record_tbl.curr_code i.e. varchar2(6). You will now be able to enforce a foreign key against schema2.mv_code_tbl.code. Note: the data in the MView column will be formatted as CHAR i.e. with trailing spaces.
You can not create relation in different type column.
Why you must create relation in database? You can connect the table using only the code.

generated by default as identity for varchar data type in sql

I have a table xx_abc with data existing in the database.
I want to add a column confi_name in this table which is mandatory column.
If i add this column like
ALTER TABLE xx_abc
ADD
( confi_NAME VARCHAR2(2000) NOT NULL);
I am getting an error :
Error report:
SQL Error: ORA-01758: table must be empty to add mandatory (NOT NULL) column
01758. 00000 - "table must be empty to add mandatory (NOT NULL) column"
So I converted it to
ALTER TABLE xx_abc
ADD
( confi_name VARCHAR2(2000) generated by default as identity (START WITH 2, INCREMENT BY 1)
But this is also throwing an error because generated by defaut has to be of int data type. I basically want to make config_name with value which is unique for each row. and i cannot change its data type as well. Any work around ?
First add the column as nullable.
Then update that column with a default value in every row.
Then set the column to be NOT NULL.
As you have mentioned, the table had their values already. If you are going to add another column with "not null" property, make sure that you insert values equal to the number of values(rows) of the previous columns since you had set it to "not null" as its properties. Another way is not to use "not null" first then set the property to "not null" once you have enough values for the column already.
you have to set a default value for the existing rows before adding the constraint.
1)Modify the table
ALTER TABLE xx_abc
ADD
( confi_NAME VARCHAR2(2000));
2)Set default values
update XX_ABC set confi_NAME = 'DEFAULT';
COMMIT;
3)Add the constraint
alter table XX_ABC add check (confi_NAME is not null);
Existing table:
SQL> CREATE TABLE t(A VARCHAR2(10));
Table created.
SQL> INSERT INTO t VALUES('a');
1 row created.
SQL> INSERT INTO t VALUES('b');
1 row created.
SQL> INSERT INTO t VALUES('c');
1 row created.
SQL> COMMIT;
Commit complete.
Add a new column:
SQL> ALTER TABLE t ADD (b VARCHAR2(10));
Table altered.
Update the rows:
SQL> UPDATE t SET b = 'newvalue';
3 rows updated.
Add NOT NULL constraint:
SQL> ALTER TABLE t MODIFY b NOT NULL;
Table altered.
SQL> desc t
Name Null? Type
----------------------------------------- -------- -------------
A VARCHAR2(10)
B NOT NULL VARCHAR2(10)
SQL>

Add new column to a table without constraint in SQL

I want to add a column with the same value across the rows to a table. I use this:
ALTER TABLE dbo.MyTable
ADD MyColumnName VARCHAR(20) NULL
DEFAULT 'A201412'
WITH VALUES
It almost works fine but it creates some stupid constraint to a column. Other existing columns do not have any constraints. How to create a column without a constraint?
That "stupid" constraint is what the DEFAULT keyword is really used for.
Using DEFAULT when you create a column means that that value will be used when no value is specified in an INSERT for the column, for example
CREATE TABLE test (
a Int
, b Varchar(5) DEFAULT 'foo'
);
INSERT INTO test(a) VALUES (1)
will generate the row
a | b
1 | foo
instead of the row
a | b
1 | NULL
As Gordon already said, don't add the DEFAULT, then use an UPDATE to put the initial value in the new column
ALTER TABLE dbo.MyTable ADD MyColumnName VARCHAR(20);
UPDATE dbo.MyTable SET MyColumnName = 'A201412'
Just don't add the default clause. Simply use:
ALTER TABLE dbo.MyTable ADD MyColumnName VARCHAR(20);

SQLPlus AUTO_INCREMENT Error

When I try and run the following command in SQLPlus:
CREATE TABLE Hotel
(hotelNo NUMBER(4) NOT NULL AUTO_INCREMENT,
hotelName VARCHAR(20) NOT NULL,
city VARCHAR(50) NOT NULL,
CONSTRAINT hotelNo_pk PRIMARY KEY (hotelNo));
I get the following error:
(hotelNo NUMBER(4) NOT NULL AUTO_INCREMENT,
*
ERROR at line 2:
ORA-00907: missing right parenthesis
What am I doing wrong?
Many will gripe about this not being a standard feature in Oracle, but when it’s as easy as two more commands after your CREATE TABLE command I can’t see any good reason to use fancy SQL on every insert.
First let’s create a simple table to play with.
SQL> CREATE TABLE test
(id NUMBER PRIMARY KEY,
name VARCHAR2(30));
Table created.
Now we’ll assume we want ID to be an auto increment field. First we need a sequence to grab values from.
SQL> CREATE SEQUENCE test_sequence
START WITH 1
INCREMENT BY 1;
Sequence created.
Now we can use that sequence in a BEFORE INSERT trigger on the table.
CREATE OR REPLACE TRIGGER test_trigger
BEFORE INSERT
ON test
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT test_sequence.nextval INTO :NEW.ID FROM dual;
END;
/
SQL> INSERT INTO test (name) VALUES ('Jon');
1 row created.
SQL> INSERT INTO test (name) VALUES (’Bork’);
1 row created.
SQL> INSERT INTO test (name) VALUES (’Matt’);
1 row created.
SQL> SELECT * FROM test;
ID NAME
———- ——————————
1 Jon
2 Bork
3 Matt
Oracle has no auto_increment, you need to use sequences.
Or - starting with Oracle 12.1 - you can simply have:
CREATE TABLE employee
(
id NUMBER GENERATED by default on null as IDENTITY
....
)