A nice way to add unique constraint to existing table for Oracles DB? - sql

There is an existing table with three columns which all form the primary key.
What is the best way to add a unique column to it? Prefferably creating a sequence for it while Im at it.

You can add an additional column to a table with an ALTER TABLE
ALTER TABLE table_name
ADD( new_column_name NUMBER UNIQUE );
You can create a new sequence and then create a trigger that populates the new column using that sequence
CREATE SEQUENCE sequence_name;
CREATE TRIGGER trigger_name
BEFORE INSERT ON table_name
FOR EACH ROW
BEGIN
:new.new_column_name := sequence_name.nextval;
END;
If you are using a version of Oracle prior to 11g, your trigger would need to do a SELECT from DUAL in order to populate the :new.new_column_name column rather than doing a direct assignment
CREATE TRIGGER trigger_name
BEFORE INSERT ON table_name
FOR EACH ROW
BEGIN
SELECT sequence_name.nextval
INTO :new.new_column_name
FROM dual;
END;
Presumably, you'd also want to initialize all the existing rows using the sequence value before you started inserting new rows
UPDATE table_name
SET new_column_name = sequence_name.nextval
WHERE new_column_name IS NULL
But it seems very odd to add a new sequence-generated column to an existing table with a composite primary key unless the goal was to use that new column as the primary key. The whole point of having a sequence generated column is so that you have a stable, synthetic primary key that doesn't depend on the actual business data. So it would seem to make much more sense to drop the existing primary key, add the new column, populate the data, declare the new column as the new primary key, and then define a unique constraint on the three columns that comprised the old primary key.

Related

How to create a surrogate key column in existing table?

I would like to create a new column called PurchaseOrderID in an existing table using SSMS. It combines LineNumber and PONUMBER to create a surrogate key and then I would enter into table design mode and assign it a PK there.
Creating new column:
ALTER TABLE FactPurchaseOrders
ADD PurchaseOrderID VARCHAR(64);
Populating with values:
UPDATE FactPurchaseOrders
SET PurchaseOrderID = (CONVERT(VARCHAR(64), LineNumber) + CONVERT(VARCHAR(64), PONUMBER))
WHERE 1=1;
Currently with this I am unable to assign this column a PK and I believe because it is nullable.
I have also tried creating it in design mode first and the same problem occurs.
That is most certainly the case. After you have run your update, simply alter the columns you will use in your PK to NOT NULL. Since the columns will have values now it can be set as NOT NULL and then it will allow the assignment of PK. Also make sure there isn't already another PK on the table already. There can be only 1!
Update Records
Alter columns to not null
Create PK on fields

SQL Oracle Determining Primary Key Values

In Oracle SQL what is the best way to create primary key values for an entity? I have been adding 100 for each different entity and incrementing new entities by 1, but I can see how this is not good because if I have over 100 inserts into a table I would reuse a primary key number. I have many tables with primary keys, how do I determine a way to make sure all of the values are unique and there is no chance of them overlapping with other primary key values?
An example of what I have been doing is as follows:
create table example (
foo_id number(5);
Constraint example_foo_id_pk Primary key (foo_id);
Insert Into example
Values(2000);
Insert Into example
Values(2010);
create table example2 (
foobar_id number(5);
Constraint example2_foobar_id_pk Primary key (foobar_id);
Insert Into example2
Values (2100);
Insert Into example2
Values (2110);
In Oracle people commonly use sequences to generate numbers. In an insert trigger, the next value of the sequence is queried and put in the primary key field. So you normally don't pass a value for that field yourself.
Something like this:
CREATE SEQUENCE seq_example;
CREATE OR REPLACE TRIGGER tib_example
BEFORE INSERT ON example
FOR EACH ROW
BEGIN
SELECT seq_example .NEXTVAL
INTO :new.foo_id
FROM dual;
END;
/
Then you can just insert a record without passing any value for the id, only for the other fields.
If you want the keys to be unique over multiple tables, you can use the same sequence for each of them, but usually this is not necessary at all. A foo and a bar can have the same numeric id if they are different entities.
If you want every entity to have a unique ID throughout your database, you might consider using GUIDs.
Try using a sequence..
CREATE SEQUENCE Seq_Foo
MINVALUE 1
MAXVALUE 99999999
START WITH 1
INCREMENT BY 1;
To use the sequence in an insert, use Seq_Foo.NextVal.
Starting with Oracle database 12C, you can use identity columns. Use something like
foobar_id number(5) GENERATED BY DEFAULT ON NULL AS IDENTITY
For older versions sequences are the recommended way, although some ORM tools offer using a table which stores the counter. Inserting via sequence can be done either with triggers or by directly inserting sequence.nnextval into your table. The latter may be useful if you need the generated ID for other purposes (like inserting into child tables).

SQLite Drop Column and Cascading Delete

I have researched how to drop a column using SQLite. Due to the lack of a DROP COLUMN statement, I am considering using the following workaround:
Delete column from SQLite table
This involves moving all data into a temporary table, dropping the original, and then re-creating it.
If I have a cascading delete dependency on the table I want to modify, how can I prevent any dependent tables from losing data?
Ex.
CREATE TABLE A (
id INTEGER PRIMARY KEY,
name TEXT,
dummy INTEGER
)
CREATE TABLE B (
id INTEGER PRIMARY KEY,
name TEXT,
a_id INTEGER,
FOREIGN KEY (a_id) REFERENCES A(id) ON DELETE CASCADE
)
Let's say I want to remove Column "dummy" from Table A, but I don't want to affect any rows in Table B. Can this be done?
Foreign key constraints can be disabled with a PRAGMA.
Just execute PRAGMA foreign_keys = off before removing records.
Cascading Deletes are based on records (rows) not attributes (columns). Removing the dummy column will not cause any cascading deletes as you are not removing any records from the parent table.

SQL: Create new column with default, unique value

I have added a new column, called Ordinal, to a table called Activity. The problem is that I gave it a UNIQUE constraint, set it to allow NULL (though this I won't want in the end.. I just needed to set it to that to get a little farther with the script), and did not give it a default value. I'm now running a RedGate SQL Compare script that was generated by comparing this table to a version of the Activity table that does not have the column. But I'm getting the following error:
The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for the object name 'iwt.Activity' and the index name 'IX_Activity'. The duplicate key value is (1).
So based on my research, it's trying to create a unique key constraint on the Ordinal column, but NULL is not unique. So my next step was to give it a unique value of 1 just to let the script pass. But 1 isn't going to be unique either. So, finally, my question:
Preferably in SQL Server Management Studio, how do I set a column as having a unique default value? Isn't that what I would need to create this constraint?
Thanks.
try this:
NULL will be the first constraint when you create the column.
UNIQUE will be as add constraint, you should add the second constraint.
they can run on this order with no problem (tested):
--first constraint
alter table Table_Name
add Column_Name int null
--second constraint
alter table Table_Name
add constraint Constraint_Name unique (Column_Name)
In my example :
PaymentGatewayHash is column
Cart is a table
--first query
alter table Cart
add PaymentGatewayHash NVARCHAR(20) null
--second query
CREATE UNIQUE INDEX PaymentGatewayHashUnique
ON Cart (PaymentGatewayHash)
WHERE PaymentGatewayHash IS NOT NULL
I just tested that :D

Oracle Schema upgrade with new constraint- how can I reduce upgrade down time?

I have a oracle repository up and running and has say 10 million records. One of the table is say
CREATE TABLE TABLE_A
NAME VARCHAR2(128),
VER VARCHAR2(128),
TYPE VARCHAR2(32),
DESCRIPTION VARCHAR2(256),
CONSTRAINT TABLE_A_PK PRIMARY KEY ("NAME","VERSION");
This table is being used for long and now say I have a requirement to change the primary key constraint. Now I have the requirement to have another column say ID and primary key to be combination of NAME, VER, TYPE and LANG.
In the upgrade script I can have something like
EXECUTE IMMEDIATE
ALTER TABLE TABLE_A ADD LANG VARCHAR2(32);
EXECUTE IMMEDIATE
UPDATE TABLE TABLE_A SET LANG ='|| 'en_US';
EXECUTE IMMEDIATE
UPDATE TABLE TABLE_A SET TYPE='||'n/a'||' WHERE TYPE IS NULL;
Before TYPE can have values and sometimes null. Since after upgrade its part of primary key it cannot be null so making it n/a if its null.
But doing above thing for 10 million records requires upgrade downtime of 5 hours atleast. Is there any other way I can make a previous column as primary key and still won't require much downtime.
Kindly also suggest me if I am wrong with my approach. Thanks in Advance
First of all, I don't understand why using EXECUTE IMMEDIATE.
Then, what about creating a PK using Enabled Novalidated Constraints, it will apply to the new inserted rows but not to the old ones. Like that you can run batch to modify existing data to commit the new PK.
Find out more :
http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/data_acc.htm#i6516
For LANG column, you could also give default value :
ALTER TABLE TABLE_A ADD LANG VARCHAR2(32) default 'en_US';
then
ALTER TABLE TABLE_A MODIFY LANG VARCHAR2(32) default null;
Nicolas.
The current primary key would have a supporting index which is probably a unique index on NAME/VERSION.
Once the columns have been added, you can create a unique index on those four columns. Then replace the primary key constraint, drop the old index (if it doesn't do so automatically when you drop the PK constraint) and use the newly created index.
It won't cut the total time, bu it may allow you to break the whole operation out into, say, 5 1-hour steps, rather than a single 5-hour step.