How to CREATE TABLE AS adding an identity? - oracle

In such way I can create table from a table adding a column number:
drop table A_TEST
/
CREATE TABLE A_TEST AS
SELECT CAST( null as NUMBER ) as ROW_ID,
C_CODE,B_CODE
FROM A
However I want to add the column as an identity how to do that ? I tried the below, but throwing an error:
CREATE TABLE A_TEST AS
SELECT CAST( null as NUMBER GENERATED BY DEFAULT AS IDENTITY ) as ROW_ID,
C_CODE,B_CODE
FROM A

You can not create the table using CTAS including the IDENTITY column.
But, You can simply create a table without an identity column using CTAS and then ALTER the table to include IDENTITY columns as following:
CREATE TABLE A_TEST
AS
SELECT
C_CODE,
B_CODE
FROM
A;
ALTER TABLE A_TEST ADD ROW_ID NUMBER
GENERATED BY DEFAULT AS IDENTITY;
Cheers!!

Do it in multiple steps: create the table from the other table without data; then alter the table to add the identity column; and finally insert the data.
Oracle Setup:
CREATE TABLE A ( A_CODE, B_CODE, C_CODE ) AS
SELECT 999, 'BBB', SYSDATE FROM DUAL UNION ALL
SELECT 0, NULL, DATE '1970-01-01' FROM DUAL;
Create Table:
Create the table without the IDENTITY column and with no rows:
CREATE TABLE A_TEST AS
SELECT C_CODE, B_CODE
FROM A
WHERE 1 = 0;
Then alter the table to add the IDENTITY column:
ALTER TABLE A_TEST ADD (
ROW_ID NUMBER
GENERATED ALWAYS AS IDENTITY
CONSTRAINT A_TEST__ROW_ID__PK PRIMARY KEY
);
Then insert the rows:
INSERT INTO A_TEST ( C_CODE, B_CODE )
SELECT C_CODE, B_CODE FROM A;
(Or you can create the table and insert the rows in the first step; and alter the table to add the identity column without a NOT NULL/PRIMARY KEY constraint in the second step; and, if you want to add a NOT NULL/PRIMARY KEY constraint afterwards then it must be done in a separate subsequent ALTER TABLE statement. db<>fiddle)
Output:
SELECT * FROM A_TEST;
C_CODE | B_CODE | ROW_ID
:------------------ | :----- | -----:
2019-12-19 09:06:27 | BBB | 1
1970-01-01 00:00:00 | null | 2
db<>fiddle here

Related

Add a primary key column to an old table

So I have a table with some 50+ rows. And currently this tables doesnot have any primary key/ID column in it. Now if I have to add a primary key column, its not allowing me to because already data are present in the table and there is as such no unique column or combination of columns. Can anyone suggest me how to add a primary column to an existing table with data in it.
(From 12.1) You can add a new auto-incremented surrogate key to a table with either:
alter table t
add ( t_id integer generated by default as identity );
Or
create sequence s;
alter table t
add ( t_id integer default s.nextval );
These set the value for all the existing rows. So may take a while on large tables!
You should also look to add a unique constraint on the business keys too though. To do that, take the steps Marmite Bomber suggests.
In your case when the table due to missing PK definition suffers some duplicated records, you may do a stepwise recovery.
In the first step you disables the creation of the new duplicated rows.
Let's assume your PK candidate columns are col1, col2 such as in the example below:
CREATE TABLE test_pk as
SELECT 'A' col1, 1 col2 FROM dual UNION ALL
SELECT 'A' col1, 2 col2 FROM dual UNION ALL
SELECT 'B' col1, 1 col2 FROM dual UNION ALL
SELECT 'B' col1, 1 col2 FROM dual;
You can not define the PK because of the existing duplications
ALTER table test_pk ADD CONSTRAINT my_pk UNIQUE (col1, col2);
-- ORA-02299: cannot validate (xxx.MY_PK) - duplicate keys found
But you can crete an index on the PK columns and set up a constraint in the state ENABLE NOVALIDATE.
This will tolerate existing duplicates, but reject the new once.
CREATE INDEX my_pk_idx ON test_pk(col1, col2);
ALTER TABLE test_pk
ADD CONSTRAINT my_pk UNIQUE (col1,col2) USING INDEX my_pk_idx
ENABLE NOVALIDATE;
Now you may insert new unique rows ...
INSERT INTO test_pk (col1, col2) VALUES ('A', 3);
-- OK
... but you can't create new duplications:
INSERT INTO test_pk (col1, col2) VALUES ('A', 1);
-- ORA-00001: unique constraint (xxx.MY_PK) violated
Later in the second step you may decide to clenup the table and VALIDATE the constraint, which will make a perfect primary key as expected:
-- cleanup
DELETE FROM TEST_PK
WHERE col1 = 'B' AND col2 = 1 AND rownum = 1;
ALTER TABLE test_pk MODIFY CONSTRAINT my_pk ENABLE VALIDATE;

insert all and inner join in oracle

I would like to insert data in to two tables. Will be one-to-many connection. For this, I have to use Foreign Key, of course.
I think, table1 - ID column is an ideal for this a Primary Key. But I generate it always with a trigger, automatically, every line. SO,
How can I put Table1.ID (auto generated, Primary Key) column in to table2.Fkey column in the same insert query?
INSERT ALL INTO table1 ( --here (before this) generated the table1.id column automatically with a trigger.
table1.food,
table1.drink,
table1.shoe
) VALUES (
'apple',
'water',
'slippers'
)
INTO table2 (
fkey,
color
) VALUES (
table1.id, -- I would like table2.fkey == table1.id this gave me error
'blue'
) SELECT
*
FROM
table1
INNER JOIN table2 ON table1.id = table2.fkey;
The error message:
"00904. 00000 - "%s: invalid identifier""
As suggested by #OldProgrammer, use sequence
INSERT ALL INTO table1 ( --here (before this) generated the table1.id column automatically with a trigger.
table1_id,
table1.food,
table1.drink,
table1.shoe
) VALUES (
<sequecename_table1>.nextval,
'apple',
'water',
'slippers'
)
INTO table2 (
fkey,
color
) VALUES (
<sequecename_table2>.nextval,
<sequecename_table1>.currval, -- returns the current value of a sequence.
'blue'
) SELECT
*
FROM
table1
INNER JOIN table2 ON table1.id = table2.fkey;
Since you're using Oracle DB's 12c version, then might use Identity Column Property. Then easily return the value of first table's (table1) to a local variable by charging of returning clause just after an insert statement for table1, and use inside the next insert statement which is for table2 as stated below :
SQL> create table table1(
2 ID integer generated always as identity primary key,
3 food varchar2(50), drink varchar2(50), shoe varchar2(50)
4 );
SQL> create table table2(
2 fkey integer references table1(ID),
3 color varchar2(50)
4 );
SQL> declare
2 cl_tab table1.id%type;
3 begin
4 insert into table1(food,drink,shoe) values('apple','water','slippers' )
5 returning id into cl_tab;
6 insert into table2 values(cl_tab,'blue');
7 end;
8 /
SQL> select * from table1;
ID FOOD DRINK SHOE
-- ------- ------- -------
1 apple water slippers
SQL> select * from table2;
FKEY COLOR
---- --------------------------------------------------
1 blue
Anytime you issue the above statement for insertions between begin and end, both table1.ID and table2.fkey columns will be populated by the same integer values. By the way do not forget to commit the changes by insertions, if you need these values throughout the DB(i.e.from other sessions also).

Convert String List to Number in Oracle DB

I am saving table ids as foreign key into another table using Oracle Apex Shuttle field like(3:4:5). Now I want to use these IDS in sql query using IN Clause. I have replaced : with , using replace function but it shows
no data found
message.
The following query works fine when I use static values.
select * from table where day_id IN(3,4,5)
But when I try to use
select * from table where id IN(Select id from table2)
it shows no data found.
From what i understand you have a list like 1:2:3:4 that you want to use in a IN clause; you can transform the list into separated values like this:
select regexp_substr('1:2:3:4','[^:]+', 1, level) as list from dual
connect by regexp_substr('1:2:3:4', '[^:]+', 1, level) is not null;
This will return:
List
1
2
3
4
Then you can simply add it to your query like this:
SELECT *
FROM TABLE
WHERE day_id IN
(SELECT regexp_substr('1:2:3:4','[^:]+', 1, level) AS list
FROM dual
CONNECT BY regexp_substr('1:2:3:4', '[^:]+', 1, level) IS NOT NULL
);
Can you try below statement. It has working as you expected.
create table table1 (id number, name varchar2(20));
alter table table1 add constraints pri_cons primary key(id);
create table table2 (id number, name varchar2(20));
alter table table2 add constraints ref_cons FOREIGN KEY(id) REFERENCES table1 (id);
begin
insert into table1 values (1,'Bala');
insert into table1 values (2,'Sathish');
insert into table1 values (3,'Subbu');
insert into table2 values (1,'Nalini');
insert into table2 values (2,'Sangeetha');
insert into table2 values (3,'Rubini');
end;
/
select * from table1 where id IN (Select id from table2);

Changing the data type of a column in Oracle

I created the following table
CREATE TABLE PLACE(
POSTCODE VARCHAR(10) PRIMARY KEY,
STREET_NAME VARCHAR(10),
COUNTY VARCHAR(10),
CITY VARCHAR(10));
I want to change the name, county and city from varchar(10) to varchar(20). How do I do that?
ALTER TABLE place
MODIFY( street_name VARCHAR2(20),
county VARCHAR2(20),
city VARCHAR2(20) )
Note that I am also changing the data type from VARCHAR to VARCHAR2 to be more conventional. There is no functional difference at present between the two though the behavior of VARCHAR may change in the future to match the SQL standard.
if you want to change only type of column use below:
ALTER TABLE <table_name> MODIFY (<column_name> <new_Type>)
in your case:
ALTER TABLE place MODIFY (street_name VARCHAR2(20),
county VARCHAR2(20),
city VARCHAR2(20))
If your table has data you could act below:
add a column with new type to table.
copy data from old column to new column.
drop old column.
rename new column to old.
For rename a column use below:
ALTER TABLE <table_name> rename column <column_name> to <new_column_name>
Oracle 10G and later
ALTER TABLE table_name
MODIFY column_name datatype;
A very general example is here to do the same -
Table:
CREATE TABLE TABLE_NAME(
ID NUMBER PRIMARY KEY,
COLUMN_NAME NUMBER NOT NULL, -- Modify with varchar2(20) NOT NULL
.
.
.
);
Step to modify the datatype of COLUMN_NAME from NUMBER to VARCHAR2
STEPS:
--Step 1: Add a temp column COLUMN_NAME_TEMP in table TABLE_NAME to hold data temporary
ALTER TABLE TABLE_NAME
ADD( COLUMN_NAME_TEMP varchar2(20) );
--Step 2: Update temp column COLUMN_NAME_TEMP with Old columns COLUMN_NAME data
UPDATE TABLE_NAME
SET COLUMN_NAME_TEMP = COLUMN_NAME;
--Step 3: Remove NOT NULL constrain from old columns COLUMN_NAME
ALTER TABLE TABLE_NAME MODIFY (COLUMN_NAME NULL);
--Step 4: Update old columns COLUMN_NAME data with NULL
UPDATE TABLE_NAME SET COLUMN_NAME = NULL;
--Step 5: Alter table old columns COLUMN_NAME to new data type varchar2(20)
ALTER TABLE TABLE_NAME MODIFY COLUMN_NAME varchar2(20);
--Step 6: Update old columns COLUMN_NAME with data from temp columns COLUMN_NAME_TEMP
UPDATE TABLE_NAME
SET COLUMN_NAME = COLUMN_NAME_TEMP;
--Step 7: Add NOT NULL constrain from old columns [COLUMN_NAME]
ALTER TABLE TABLE_NAME MODIFY (COLUMN_NAME NOT NULL);
--Step 8: Drop the temp column [COLUMN_NAME_TEMP]
alter table TABLE_NAME drop column COLUMN_NAME_TEMP;
If NOT NULL constrain is not exist the omitte step-3 and step-7
Alter table placemodify(street name varchar2(20),city varchar2(20)
You can't modify the data type of a table if you have some amount of records already present in the table.
You have to empty the table records of the column (you want to modify the data type) first and then use the below command :
alter table place
modify ( street_name varchar2(20), country varchar2(20), city varchar2(20) );
Definitely it will work!

How can I import a partition from one table into another in Oracle?

I would like to know if the following steps are possible and how fast this is:
Create a partition named part1 in Table A
Drop partition part1 in Table B
Import the Table A partition part1 into Table B
Can you provide me with an example if it is possible indeed? Or any resources I can look at?
Note that the tables would have the exact same structure.
You can do something similar with the ALTER TABLE ... EXCHANGE PARTITION command. This would exchange a single partition with a table that has the same structure.
A little example:
/* Partitionned Table Creation */
SQL> CREATE TABLE table_a (
2 ID NUMBER PRIMARY KEY,
3 DATA VARCHAR2(200)
4 )
5 PARTITION BY RANGE (ID) (
6 PARTITION part100 VALUES LESS THAN (100),
7 PARTITION part200 VALUES LESS THAN (200)
8 );
Table created
/* Swap table creation */
SQL> CREATE TABLE swap_table (
2 ID NUMBER PRIMARY KEY,
3 DATA VARCHAR2(200)
4 );
Table created
SQL> INSERT INTO swap_table SELECT ROWNUM, 'a' FROM dual CONNECT BY LEVEL <= 99;
99 rows inserted
SQL> select count(*) from table_a partition (part100);
COUNT(*)
----------
0
This will exchange the partition part100 with the transition table swap_table:
SQL> ALTER TABLE table_a EXCHANGE PARTITION part100 WITH TABLE swap_table;
Table altered
SQL> select count(*) from table_a partition (part100);
COUNT(*)
----------
99

Resources