In which cases will Oracle create indexes automatically? - database

As far as I know (this page) Oracle automatically creates an index for each UNIQUE or PRIMARY KEY declaration. Is this a complete list of cases when indexes are created automatically in Oracle?

I'll try to consolidate given answers and make it community wiki.
So indexes are automatically created by Oracle for such cases:
APC: For primary key and unique key unless such indexes already exist.
APC: For LOB storage and XMLType.
Gary: For table with a nested table.
Jim Hudson: For materialized view.

Firstly, Oracle does not always create an index when we create a primary or unique key. If there is already an index on that column it will use it instead...
SQL> create table t23 (id number not null)
2 /
Table created.
SQL> create index my_manual_idx on t23 ( id )
2 /
Index created.
SQL> select index_name from user_indexes
2 where table_name = 'T23'
3 /
INDEX_NAME
------------------------------
MY_MANUAL_IDX
SQL>
... note that MY_MANUAL_IDX is not a unique index; it doesn't matter ...
SQL> alter table t23
2 add constraint t23_pk primary key (id) using index
3 /
Table altered.
SQL> select index_name from user_indexes
2 where table_name = 'T23'
3 /
INDEX_NAME
------------------------------
MY_MANUAL_IDX
SQL> drop index my_manual_idx
2 /
drop index my_manual_idx
*
ERROR at line 1:
ORA-02429: cannot drop index used for enforcement of unique/primary key
SQL>
There is another case when Oracle will automatically create an index: LOB storage....
SQL> alter table t23
2 add txt clob
3 lob (txt) store as basicfile t23_txt (tablespace users)
4 /
Table altered.
SQL> select index_name from user_indexes
2 where table_name = 'T23'
3 /
INDEX_NAME
------------------------------
MY_MANUAL_IDX
SYS_IL0000556081C00002$$
SQL>
edit
The database treats XMLType same as other LOBs...
SQL> alter table t23
2 add xmldoc xmltype
3 /
Table altered.
SQL> select index_name from user_indexes
2 where table_name = 'T23'
3 /
INDEX_NAME
------------------------------
MY_MANUAL_IDX
SYS_IL0000556081C00002$$
SYS_IL0000556081C00004$$
SQL>

No, we're getting closer but that's not quite a complete list yet.
There will also be an index automatically created when you create materialized view since Oracle needs to be able to quickly identify the rows when doing a fast refresh. For rowid based materialized views, it uses I_SNAP$_tablename. For primary key materialized views, it uses the original PK name, modified as necessary to make it unique.
create materialized view testmv
refresh force with rowid
as select * from dual;
select index_name from user_indexes where table_name = 'TESTMV';
Index Name
--------------
I_SNAP$_TESTMV

And another one, if you create a table with a nested table you get an index created automatically. Object based storage in general can do this as there can be hidden tables created.
I think schema-based XMLTypes will also do it.

Yes, that's the complete list. Oracle automatically creates an index for each UNIQUE or PRIMARY KEY declaration.

Related

Practices regarding Nullable Foreign Keys & Alternatives to it

I am currently working on designing and implementing a database.
We are running a conference, and there are two ways for attendees to register to the conference. The first is that the register and pay online - quite straightforward. The second is that they physically attend a "registration day" where they pay cash, and are added by one of our many admins. In this case, we would like to keep track of which admin added the attendee - for internal purposes.
We believe that it is best to store all attendees in the same table, and we would need a foreign key to track the admin that each attendee was added by. But for attendees registering online and paying themselves, we simply want to indicate that they were not added by any admin (so the foreign key would be Null).
Is the proposed idea of nullable foreign keys bad practice? Are there any benefits to storing attendees in different tables, where attendees registering online do not have a column for addedBy at all and cash-paying attendees have a non-nullable addedBy column?
I wouldn't store attendees in two (or more?) separate tables. They belong into the same table, and there should be a column which will tell you how someone got registered. Will it be "admin name" (or ID), checkbox, radio button item, whatever - just keep them in the same table.
Why? Because currently you think of two tables. It means that all code you write will have to be "duplicated" for those two tables - all inserts, updates, selects ... everything.
Now imagine that someone gets a super idea of the 3rd way of registration (snail mail, for example). What will you do then? Create the 3rd table, and triple code you wrote? That would be a really bad practice.
There's nothing "wrong" if a foreign key column doesn't contain any value, if you decide to do so - just document it. For example (Oracle syntax; would be similar in any other database):
SQL> create table admins
2 (id_admin number constraint pk_adm primary key,
3 name varchar2(20) not null
4 );
Table created.
SQL> create table attendees
2 (id_attendee number constraint pk_att primary key,
3 name varchar2(20) not null,
4 id_admin number constraint fk_att_adm references admins (id_admin)
5 );
Table created.
A few sample rows:
SQL> -- admin
SQL> insert into admins (id_admin, name)
2 select 1, 'Little' from dual;
1 row created.
SQL> -- attendees
SQL> -- registered online
SQL> insert into attendees (id_attendee, name) values (1, 'Mike');
1 row created.
SQL> -- registered on site
SQL> insert into attendees (id_attendee, name, id_admin) values (2, 'Scott', 1);
1 row created.
What do we know about them? It has to be outer join because - if it's not - you won't get info about people registered online:
SQL> select t.id_attendee, t.name attendee, a.name registered_by
2 from attendees t left join admins a on a.id_admin = t.id_admin;
ID_ATTENDEE ATTENDEE REGISTERED_BY
----------- -------------------- --------------------
1 Mike
2 Scott Little
SQL>
If you don't want to allow NULL values for a foreign key column, then a simple (and not bad at all) option is to create a "dummy" admin (let's call it "Online"):
SQL> insert into admins (id_admin, name) values (0, 'Online');
1 row created.
Set it for all users registered online (their id_admin column value is NULL):
SQL> update attendees set id_admin = 0 where id_admin is null;
1 row updated.
Disallow NULL values for a foreign key column:
SQL> alter table attendees modify id_admin not null;
Table altered.
Now you can use inner (instead of outer) join:
SQL> select t.id_attendee, t.name attendee, a.name registered_by
2 from attendees t join admins a on a.id_admin = t.id_admin;
ID_ATTENDEE ATTENDEE REGISTERED_BY
----------- -------------------- --------------------
1 Mike Online
2 Scott Little
SQL>
Snail mail? No problem, you don't have to modify any code you wrote so far:
SQL> insert into admins (id_admin, name) values (3, 'Snail mail');
1 row created.
SQL> insert into attendees (id_attendee, name, id_admin) values (3, 'King', 3);
1 row created.
SQL> select t.id_attendee, t.name attendee, a.name registered_by
2 from attendees t join admins a on a.id_admin = t.id_admin;
ID_ATTENDEE ATTENDEE REGISTERED_BY
----------- -------------------- --------------------
1 Mike Online
2 Scott Little
3 King Snail mail
SQL>

Will deleting column data reduce database size?

I have a table with several columns, one of which is a CLOB containing large XML project file data. That one column accounts for 99% of the size of that table, and the table has grown to several Gb. Our DBA needs to migrate the database and wants to reduce the size as much as possible beforehand. We can't lose any rows from that table but we would be safe in clearing out the data in that particular CLOB column. Would updating the table to remove that data reduce the overall size (I assume if it did it would be in conjunction with some administrative re-indexing action or something)?
If you don't need any CLOB data, drop that column:
SQL> create table test
2 (id number,
3 cclob clob);
Table created.
SQL> insert into test (id, cclob) values (1, 'Littlefoot');
1 row created.
SQL> alter table test drop column cclob;
Table altered.
SQL>
Alternatively, create a new table with primary key column and CLOB column:
SQL> desc test
Name Null? Type
----------------------------------------- -------- ------------------
DEPTNO NUMBER(2)
DNAME VARCHAR2(14)
LOC VARCHAR2(13)
CCLOB CLOB
SQL> create table new_test as select deptno, cclob from test;
Table created.
SQL> alter table test drop column cclob;
Table altered.
SQL>
Now you can move the new, lightweight table to another server. If you need some of CLOB data, you can update the new table (on a new server) as
SQL> update test_on_new_server a set
2 a.cclob = (select b.cclob
3 from test_from_old_server b
4 where b.deptno = a.deptno
5 )
6 where a.loc = 'NEW YORK';

insert rows to table with PRIMARY KEY from different tables without PRIMARY KEY sql server

I hope to explain very well my problem
I have a new table with a Primary Key.
How to insert the table from different tables?
my problem is the one table without Primary Key and I don't know how to select from table one row and insert to the new table.
Example -
new table 1
image
AssetId is Primary key
table 2
image
I need to insert one row to table 1
table 3 image
my script -
insert AssetBusStops (AssetId,StopCode,StopId,Description,ZoneId)
select Assets.Id,stops_ppp.stop_code,stops_ppp.stop_id,stops_ppp.stop_desc,stops_ppp.zone_id from Assets inner join stops_ppp
on Assets.AssetCode = stops_ppp.stop_code
Exception -
Msg 2627, Level 14, State 1, Line 11
Violation of PRIMARY KEY constraint 'PK_AssetBusStops'. Cannot insert duplicate key in object 'dbo.AssetBusStops'. The duplicate key value is (2763).
The statement has been terminated.
The value 20001 of the column AssetCode of the table Assets matches 3 rows from the table stops_ppp and these 3 rows in the result joined query have the same value 2763 in the column id.
So your query tries to insert 3 rows, not just 1 and this would create duplicates in the primary key, which is not allowed.
You should apply a filter in the results of the query, something like:
insert AssetBusStops (AssetId,StopCode,StopId,Description,ZoneId)
select top 1 ASsets.Id,
stops_ppp.stop_code, stops_ppp.stop_id, stops_ppp.stop_desc, stops_ppp.zone_id
from Assets inner join stops_ppp
on Assets.AssetCode = stops_ppp.stop_code
order by stops_ppp.stop_code
This (for your sample data) returns only 1 row (an arbitrary ow as you requested in the comments) and can be safely inserted.
A) If you don't have FK to table AssetBusStops :
Change PK Column to IDENTITY(1,1)
Remove PK value from Insert script
B) If you have FK to table AssetBusStops :
try to use Not Exists or Merge

The foreign key constraint

I have a table which contained the following columns.
ID int PK
Name nvarchar(50) NotNull
FID int FK reference to ID
ID Name PK
1 A Null
2 B Null
3 C 1
4 D 1
5 E 1
6 F 2
So, The primary key includes as a primary key in a table. I want to do that if the primary key is deleted, the rows which is contained the primary key as a foreign is deleted automatically. (example: When I delete ID 1 row, I want to delete automatically ID 3, 4, 5 rows.). How to make that the primary key is included as a foreign key in a table? How can I do this. Thanks.
You need to implement a "trigger" that does a "cascading delete".
Here's a good link:
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=142564
CREATE TRIGGER test_trig
ON dbo.Table_1
FOR DELETE
AS
BEGIN
delete a from dbo.Table_2 a
JOIN
deleted d
ON a.joincol = d.joincol
END
Here are some other alternatives:
http://www.mssqltips.com/sqlservertip/1508/foreign-key-vs-trigger-referential-integrity-in-sql-server/
And here is a link to Microsoft's documentation on "Cascading Referential Integrity Constraints":
http://msdn.microsoft.com/en-us/library/ms186973.aspx
NOTE: In Microsoft SQL, a cascading delete to a self-referencing table is not allowed. You must either use a trigger, create a stored procedure, or handle the cascading delete from the calling application. An example of this is where a single table has an ID as identity and a ParentID with a relationship to ID in the same table.
see here
The only way will be to add a trigger you can refer the following links for more information.
http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataproviders/thread/b777ec73-e168-4153-a669-835049a96520
another link

How write Alter Table and add new columns?

I have a table that has 3 columns A,B,C which has rows also. Column A is the primary key.
Now as per new requirement I need to add new column D, E and F.
Also i need to remove the previous primary key from column A and add a new primary key for column D.
Column E and F is NULL.
Please help me to create alter table statement.
What you require is a multi-step process. Adding the columns, dropping the existing primary key constraint and finally adding a new one.
The most difficult thing here is adding column D. Because you want it to be the new primary key it will have to be NOT NULL. If your table has existing data you will need to handle this error:
SQL> alter table your_table
2 add ( d number not null
3 , e date
4 , f number )
5 /
alter table your_table
*
ERROR at line 1:
ORA-01758: table must be empty to add mandatory (NOT NULL) column
SQL>
So, step 1 is add the new columns with D optional; then populate it with whatever key values:
SQL> alter table your_table
2 add ( d number
3 , e date
4 , f number )
5 /
Table altered.
SQL> update your_table
2 set d = rownum
3 /
1 row updated.
SQL>
Now we can make column D mandatory:
SQL> alter table your_table
2 modify d not null
3 /
Table altered.
SQL>
Finally, we can change the primary key column from A to D:
SQL> alter table your_table
2 drop primary key
3 /
Table altered.
SQL> alter table your_table
2 add constraint yt_pk primary key (d)
3 /
Table altered.
SQL>
For some alterations we want to add a column with a default value. In this scenario it is possible to do so in one step:
alter table your_table
add new_col varchar2(1) default 'N' not null;
In later versions of Oracle this is actually an extremely efficient of populating the new column with the same value, considerably faster than the multi-step approach outlined above.
In case it's not clear the above syntax is Oracle. I expect SQL Server will be something similar.

Resources