Disabling the Not-Nullable field in ORACLE to insert NULL data - sql

I have to add some NULL data into an otherwise not-nullable field. I checked :-
ALTER TABLE <table_name> DROP <default_constraint_name> ;
ALTER TABLE <table_name> ALTER COLUMN <column_name> <data_type> NULL;
ALTER TABLE <table_name> DROP COLUMN <column_name>;
but only the middle one seems fit for my usage because all I want o do is alter instead of . But it does not work. I am using Oracle 11g. Could you suggest anyother method or suggest what mistake I am doing in the 2nd ALTER TABLE SQL?

you can just disable constraint. And then enable it back when you want.
alter table
table_name
ENABLE constraint
constraint_name;
alter table
table_name
DISABLE constraint
constraint_name;

As stated in comment above, it may be a bad idea to allow NULLs in a column that previously did not allow them. Queries or code that already exist may rely on the assumption that the field cannot contain NULL, and could experience various problems if that assumption becomes false (errors if you're lucky, quietly producing incorrect or incomplete results if you're not).
That said, the syntax to simply remove the NOT NULL constraint permanently is:
ALTER TABLE table_name MODIFY column_name NULL;
You can also merely disable the constraint as indicated in another answer. To do this you need the constraint name which you can find by querying USER_CONSTRAINTS. This makes more sense if you expect to enable the constraint later.

Related

SQL Server : check column has member for other column but not others

The topic/header is not that intuitive, I just have to make an example
Let's assume we have a table called ARTICLE like this:
ARTICLE (idArticle, IdConference, IdMagazine, DateSent, Title, Sector);
Question: insert a constraint such that idArticle has only an IdConference or only an IdMagazine - but never both.
Straight away I knew it will be something like:
Alter table Article
add constraint checkidArt check( )
but I'm at a loss how to specify that column IdArticle should have only an IdConference or only an IdMagazine value.
Assuming it's SQL Server, since MySQL does not have check constraints:
ALTER TABLE Article
ADD CONSTRAINT checkidArt CHECK (IdConference IS NULL OR IdMagazine IS NULL)
If you are using MySQL then it won't be possible to add a constraint as MySQL does not support CHECK constraint. Here's the documentation:
The CHECK clause is parsed but ignored by all storage engines.
So, your only option would be to use a TRIGGER with SIGNAL SQLSTATE and MESSAGE_TEXT to flag the error.

PostgreSQL column type conversion from bigint to bigserial

When I try to change the data type of a column in a table by alter command...
alter table temp alter column id type bigserial;
I get
ERROR: type "bigserial" does not exist
How can I change the datatype from bigint to bigserial?
As explained in the documentation, SERIAL is not a datatype, but a shortcut for a collection of other commands.
So while you can't change it simply by altering the type, you can achieve the same effect by running these other commands yourself:
CREATE SEQUENCE temp_id_seq;
ALTER TABLE temp ALTER COLUMN id SET NOT NULL;
ALTER TABLE temp ALTER COLUMN id SET DEFAULT nextval('temp_id_seq');
ALTER SEQUENCE temp_id_seq OWNED BY temp.id;
Altering the owner will ensure that the sequence is removed if the table/column is dropped. It will also give you the expected behaviour in the pg_get_serial_sequence() function.
Sticking to the tablename_columnname_seq naming convention is necessary to convince some tools like pgAdmin to report this column type as BIGSERIAL. Note that psql and pg_dump will always show the underlying definition, even if the column was initially declared as a SERIAL type.
As of Postgres 10, you also have the option of using an SQL standard identity column, which handles all of this invisibly, and which you can easily add to an existing table:
ALTER TABLE temp ALTER COLUMN id
ADD GENERATED BY DEFAULT AS IDENTITY
ALTERing a column from BIGINTEGER to BIGSERIAL in order to make it auto-increment won't work. BIGSERIAL is not a true type, it is a trick that automates PK and SEQUENCE creation.
Instead you can create a sequence yourself, then assign it as the default for a column:
CREATE SEQUENCE "YOURSCHEMA"."SEQNAME";
ALTER TABLE "YOURSCHEMA"."TABLENAME"
ALTER COLUMN "COLUMNNAME" SET DEFAULT nextval('"YOURSCHEMA"."SEQNAME"'::regclass);
ALTER TABLE "YOURSCHEMA"."TABLENAME" ADD CONSTRAINT pk PRIMARY KEY ("COLUMNNAME");
This is a simple workaround:
ALTER TABLE table_name drop column column_name, add column column_name bigserial;
Sounds like alot of professionals out there on this subject... if the original table did indeed have data then the real answer to this dilemma is to have designed the db correctly in the first place. However, that being the case, to change the column rule (type) would require integrity verification of that column for the new paradigm. And, don't forget, anywhere where that column is manipulated (added/updated) then that would need to be looked into.
If it's a new table then okay, simples: delete column and re-add new column (takes care of the sequence for you). Again, design, design, design.
I think we've all fouled on this.

Is there a way to change all char(1) columns to number(1) columns in Oracle?

We use char(1) columns to store Boolean values in Oracle, where the value is either "1" or "0" to represent true or false. However, I want to change these to number(1) columns, where the value is either 1 or 0. It seems you cannot change the type of this column if there are already existing values in the table. So I have to do something like this:
ALTER TABLE TPM_TRAININGPLANSOLUTIONS DROP CONSTRAINT SYS_C0010178;
ALTER TABLE TPM_TRAININGPLANSOLUTIONS RENAME COLUMN ISMARKERCOMPLETION TO ISMARKER_CHAR;
ALTER TABLE TPM_TRAININGPLANSOLUTIONS ADD (ISMARKERCOMPLETION NUMBER(1) NOT NULL);
UPDATE TPM_TRAININGPLANSOLUTIONS SET ISMARKERCOMPLETION = ISMARKER_CHAR; -- This takes about 10 min
ALTER TABLE TPM_TRAININGPLANSOLUTIONS DROP COLUMN ISMARKER_CHAR; -- Also very slow
ALTER TABLE TPMDBO.TPM_TRAININGPLANSOLUTIONS
ADD ( CONSTRAINT SYS_C0010178
CHECK (ISMARKERCOMPLETION in (0,1))
NOT DEFERRABLE INITIALLY IMMEDIATE VALIDATE );
However, we have dozens of these columns in our database. Is there a faster way to do this?
There's no simple way to do what you are doing; you could using the system tables to generate the DDL for you but you still need to know the column names. However, there are simpler ways to map it to a number, without changing anything.
Firstly, you need to ensure that your columns are actually the values you've assigned.
ALTER TABLE TPMDBO.TPM_TRAININGPLANSOLUTIONS
ADD ( CONSTRAINT chk_TPM_TRAININGPLANSOLUTIONS_IMC
CHECK (ISMARKERCOMPLETION in ('0','1'))
NOT DEFERRABLE INITIALLY IMMEDIATE VALIDATE );
You can then either create a virtual column on the table:
alter table tpm_trainingplansolutions add (
ismarkercompletion_num generated always as (to_number(ismarkercompletion)) virtual
);
Or a view on top of the tables, which casts that particular column to a NUMBER.
Either would probably result in a little less work, but now much as you need to know the column names. Do what you're doing and ensure your database is correct.
As an aside, you're creating a constraint with the prefix SYS_, please don't do this... create constraints with meaningful names and don't try to mimic Oracle.
If you want to change all CHAR(1) columns you can use USER_TAB_COLUMNS to identify those columns that have this characteristic and use it to generate your DDL for you, e.g.
select 'ALTER TABLE '
|| table_name
|| ' RENAME COLUMN '
|| column_name
|| ' TO ' || substr(column_name, 1, length(column_name) - 5)
|| '_CHAR ;'
from user_tab_columns
where data_type = 'CHAR'
and data_length = 1
You'll probably have to use USER_CONS_COLUMNS as well...
If you have a lot of columns i think what you should do is
disable all constraints of the base table
create as select a new table from the base table with the desired column data types
copy the constraints from the base table
replace the base table with the new table
Altering the table one column at a time can cause a lot of issues like fragmentation and chaining. To keep the db healthy you'll be forces to rebuild it any way. So, You might as well do it the right way from the start.

Best way to add a new column with an initial (but not default) value?

I need to add a new column to a MS SQL 2005 database with an initial value. However, I do NOT want to automatically create a default constraint on this column. At the point in time that I add the column the default/initial value is correct, but this can change over time. So, future access to the table MUST specify a value instead of accepting a default.
The best I could come up with is:
ALTER TABLE tbl ADD col INTEGER NULL
UPDATE tbl SET col = 1
ALTER TABLE tbl ALTER COLUMN col INTEGER NOT NULL
This seems a bit inefficient for largish tables (100,000 to 1,000,000 records).
I have experimented with adding the column with a default and then deleting the default constraint. However, I don't know what the name of the default constraint is and would rather not access sysobjects and put in database specific knowledge.
Please, there must be a better way.
To add the column with a default and then delete the default, you can name the default:
ALTER TABLE tbl ADD col INTEGER NOT NULL CONSTRAINT tbl_temp_default DEFAULT 1
ALTER TABLE tbl drop constraint tbl_temp_default
This filled in the value 1, but leaves the table without a default. Using SQL Server 2008, I ran this and your code, of alter update alter and did not see any noticeable difference on a table of 100,000 small rows. SSMS would not show me the query plans for the alter table statements, so I was not able to compare the resources used between the two methods.
I'd ALTER TABLE tbl ADD col INTEGER CONSTRAINT tempname DEFAULT 1 first,, and drop the explicitly named constraint after (presumably within a transaction).
Another, maybe more native, way would be:
ALTER TABLE tbl ADD COLUMN col INTEGER NOT NULL DEFAULT 1;
ALTER TABLE tbl ALTER COLUMN col DROP DEFAULT;
I'm not sure how long this function exists, but the PostgreSQL documentation goes back to version 7.1 and for 7.1 it is already described.
You can do it in an insert trigger
If you add a default constraint when creating the table, you won't know what it is called. However, if you add a constraint with ALTER TABLE, you must name the constraint. In this case, you would be able to ALTER TABLE DROP CONSTRAINT (This applies to T-SQL, not sure about other databases.)
However, this would require you to CREATE TABLE with NULL column, ALTER TABLE to add the constraint, make the column NOT NULL, and finally DROP CONSTRAINT.
I don't believe an insert trigger would work as someone else mentioned, because your rows are already added.
I think the way you describe may, in fact, be the most efficient and elegant solution.

Can you replace or update a SQL constraint?

I have written the following constraint for a column I've called 'grade':
CONSTRAINT gradeRule CHECK grade IN (‘easy’, ‘moderate’, ‘difficult’),
Is it possible to later update the gradeRule to have different values? For example, 'moderate' and 'difficult' could be changed to 'medium' and 'hard'.
Thanks
You could drop the existing constraint, and add the new constraint with the NOCHECK option. This would allow you to add the constraint even though data in the table violates the constraint. The problem with doing this though would be that you wouldn't be able to update existing records without making them pass the constraint first.
ALTER TABLE SomeTable DROP CONSTRAINT gradeRule
GO
ALTER TABLE SomeTable ADD CONSTRAINT gradeRule ... WITH NOCHECK
GO
Although this is possible, its not usually recommended because of the potential problems with future updates of the data.
Drop the constraint, and then add the replacement constraint.
You can't update a constraint in SQL Server at least.
ALTER TABLE SomeTable DROP CONSTRAINT gradeRule
In addition, you'll need to update the table data before adding the new constraint, so that it meets the new constraint.
If you change the constraint, all of the data currently in the table must meet the constraint. So if you had 2 rows of data with 'moderate' and tried to change the constraint to easy, medium, and hard, it would not let you.
So you would have to make the new constraint (easy, moderate, medium, difficult, hard) or, update the data to the new values - moderate --> medium etc.