What is the best way of creating a unique identifier name in Oracle? - oracle

I want to create a check constraint on several thousand columns in a database, but all constraints needs a name that is unique in the database. I wanted to use a guid, but because of limitations in Oracle, the name can't be longer than 30 characters.
Here is an example of the syntax:
CREATE TABLE mytable
(
col1 DATE
DEFAULT to_date('19000101', 'yyyymmdd')
CONSTRAINT unique_name_needed CHECK(col1 = TRUNC(col1))
NOT NULL
)

We use a 3 letter short name for every table. These three letters we use to name our constraints. So the short name for mytable could be mtb.
Constraint names are then:
Primary: mtb_pk
Unique: mtb_uk
Foreign: mtb_otb_fk where otb is the short name of the other table.
The trick of course is to come up with unique short names for every table.

Related

ORA-02264: name already used by an existing constraint (error)

CREATE TABLE Flight (
FlightNo int NOT NULL PRIMARY KEY,
FlightDate Date,
PlaneSerialNo int,
EmployeeID int,
RouteNo int,
CONSTRAINT FK_PlaneSerialNo FOREIGN KEY(PlaneSerialNo)
REFERENCES Plane(PlaneSerialNo),
CONSTRAINT FK_EmployeeID FOREIGN KEY(EmployeeID)
REFERENCES Employee(EmployeeID),
CONSTRAINT FK_RouteNo FOREIGN KEY(RouteNo)
REFERENCES Route(RouteNo)
);
trying to create a sort of database system using oracle where it tracks flights but it just says the name is already used but havent seen any similarities in constraints other than identifying FKs
Oracle doesn't rely much on similarities - it has found object with exactly the same name in its dictionary and - as you can't have two objects with the same name - it raised the error.
Query user_constraints (and then user_objects, if previous search didn't find anything).
If you want to find out which table it is, you might try
select owner, table_name from dba_constraints where constraint_name = '<some value from your create table command>';

fast comparison a list with itself

I have a list giant list (100k entries) in my database. Each entry contains a id, text and a date.
I created a function to compare two text as possible. How it looks like is not necessary right now.
Is there a "good" way to remove "duplicates" (as possible) from the list by text?
Currently I'm looping through the list twice and compare each entry with each entry, except itself by id.
If your question is when you insert a row in the table... you can include the unique constraint.
Postgresql
CREATE TABLE table1 (
id serial PRIMARY KEY,
txt VARCHAR (50),
dt timestamp,
UNIQUE(txt)
);
Oracle
CREATE TABLE table1
( id numeric(10) NOT NULL,
txt varchar2(50) NOT NULL,
date timestamp,
CONSTRAINT txt_unique UNIQUE (txt)
);

one attribute referencing, attributes in two different tables

I have 4 tables
customer: CustomerID - primary key, name
Magazine: name - primary key, cost, noofissues
Newspaper: name - primary key, cost, noofissues
subscription: custID - references CustomerID of Customer, name, startdate, enddate
In the above, can I reference the name from subscription table to reference name from Magazine and name from Newspaper?
I have created the tables Customer, Newspaper and Magazine. I only need to create Subscription.
Can you do something like this?
CREATE TABLE subscription (
custID INT
CONSTRAINT subscription__custid__fk REFERENCES Customer( CustomerId ),
name VARCHAR2(50)
CONSTRAINT subscription__mag_name__fk REFERENCES Magazine( Name )
CONSTRAINT subscription__news_name__fk REFERENCES Newspaper( Name ),
startdate DATE
CONSTRAINT subscription__startdate__nn NOT NULL,
enddate DATE
);
Yes, you can and you will have two foreign keys on the same column pointing to different tables but if the value in the column is non-null then it will expect there to be a matching name in both the magazines table and the newspapers table - which is probably not what you are after.
Can you have a foreign key that asks can the value be in either exclusively in this table or that table (but not in both)? No.
But you can re-factor your database so you merge the newspapers and magazines tables into a single table (which you can then easily reference); like this:
CREATE TABLE customer (
CustomerID INT
CONSTRAINT customer__CustomerId__pk PRIMARY KEY,
name VARCHAR2(50)
CONSTRAINT customer__name__nn NOT NULL
);
CREATE TABLE Publications (
id INT
CONSTRAINT publications__id__pk PRIMARY KEY,
name VARCHAR2(50)
CONSTRAINT publications__name__nn NOT NULL,
cost NUMBER(6,2)
CONSTRAINT publications__cost__chk CHECK ( cost >= 0 ),
noofissues INT,
type CHAR(1),
CONSTRAINT publications__type__chk CHECK ( type IN ( 'M', 'N' ) )
);
CREATE TABLE subscription (
custID INT
CONSTRAINT subscription__custid__fk REFERENCES Customer( CustomerId ),
pubID INT
CONSTRAINT subscription__pubid__fk REFERENCES Publications( Id ),
startdate DATE
CONSTRAINT subscription__startdate__nn NOT NULL,
enddate DATE
);
If you are asking whether you can create a foreign key constraint on subscription that references either the newspaper table or the magazine table, the answer is no, you cannot. A foreign key must reference exactly one primary key.
Since magazine and newspaper have the same set of attributes, the simple option is to combine them into a single periodical table with an additional periodical_type column to indicate whether it is a magazine or a newspaper. You could then create your foreign key to the periodical table.
Although it probably won't make sense in this particular example, you could also have separate columns in subscription for magazine_name and newspaper_name and create separate foreign key constraints on those columns along with a check constraint that ensured that exactly one of the values was non-NULL. That might make sense if the two different parent tables had radically different attributes.
Not related to your question but as a general bit of advice, I wouldn't use the name as the primary key. In addition to being rather long, names tend to change over time and names aren't necessarily unique. I would use a different attribute for the key, potentially a synthetic primary key generated from a sequence.

Unique case insensitive constraint in oracle database

I have a varchar column in my table for url value. I have to make it unique across the records case-insensitively.
I found 2 ways to achieve it.
Create an unique index on the field.
create unique index <index_name> on <tablename>(lower(<column_name>))
Add a unique constraint on the field as
ALTER TABLE person ADD CONSTRAINT person_name_unique
UNIQUE(LOWER(first_name),LOWER(last_name));
What is the efficient way to adopt from the above choices ?
The more efficient approach is the first approach. It's more efficient, though, only because the latter syntax doesn't work. You cannot, unfortunately, create a function-based constraint in the same way that you can create a unique index.
A unique constraint doesn't work
SQL> create table person (
2 first_name varchar2(10),
3 last_name varchar2(10)
4 );
Table created.
SQL> ALTER TABLE person ADD CONSTRAINT person_name_unique
2 UNIQUE(LOWER(first_name),LOWER(last_name));
UNIQUE(LOWER(first_name),LOWER(last_name))
*
ERROR at line 2:
ORA-00904: : invalid identifier
A unique function-based index, however, does work
SQL> create unique index idx_uniq_name
2 on person( lower(first_name), lower(last_name) );
Index created.
1 is possible and gives error for duplicate.
2 is not possible. (function is not possible in constraint)

Sequence with variable

In SQL we will be having a sequence. But it should be appended to a variable like this
M1,M2,M3,M4....
Any way of doing this ?
Consider having the prefix stored in a separate column in the table, e.g.:
CREATE TABLE mytable (
idprefix VARCHAR2(1) NOT NULL,
id NUMBER NOT NULL,
CONSTRAINT mypk PRIMARY KEY (idprefix, id)
);
In the application, or in a view, you can concatenate the values together. Or, in 11g you can create a virtual column that concatenates them.
I give it 99% odds that someone will say "we want to search for ID 12345 regardless of the prefix" and this design means you can have a nice index lookup instead of a "LIKE '%12345'".
select 'M' || my_sequence.nextval from dual;

Resources