how to generate primary key values while inserting data into table through pl/sql stored procedure - sql

I need to insert data into particular table through pl/sql stored procedure. My requirements are:
while inserting it should generate PRIMARY KEY values for a particular column;
it should return that PRIMARY KEY value to an output variable; and
for another column it should validate my string such that it should contain only characters, not integers.

You can generate primary key values as a surrogate key using an Oracle SEQUENCE. You can create a constraint on a column that uses TRANSLATE to check that no numeric digits exist in newly inserted/updated data.
Some example code, suitable for SQL*Plus:
CREATE SEQUENCE mysequence;
/
CREATE TABLE mytable (
pkidcol NUMBER PRIMARY KEY,
stringcol VARCHAR2(100)
);
/
ALTER TABLE mytable ADD (
CONSTRAINT stringnonnumeric
CHECK (stringcol = TRANSLATE(stringcol,'A0123456789','A'))
);
/
DECLARE
mystring mytable.stringcol%TYPE := 'Hello World';
myid mytable.pkidcol%TYPE;
BEGIN
INSERT INTO mytable (pkidcol, stringcol)
VALUES (mysequence.NEXTVAL, mystring)
RETURNING pkidcol INTO myid;
END;
/

In oracle I believe the "identity" column is best achieved with a sequence and an insert trigger that checks if the primary key columns is null and if so gets the next sequence and inserts it.
you can then use the "returning" clause to get the newly created primary key:
insert into <table> (<columns>) values (<values>) returning <prim_key> into <variable>;
the filtering of the string field I would personally handle in code before going to the database (if that is a possibility). Databases are notoriously inefficient at handling string operations.

Related

Restoring a Truncated Table from a Backup

I am restoring the data of a truncated table in an Oracle Database from an exported csv file. However, I find that the primary key auto-increments and does not insert the actual values of the primary key constrained column from the backed up file.
I intend to do the following:
1. drop the primary key
2. import the table data
3. add primary key constraints on the required column
Is this a good approach? If not, what is recommended? Thanks.
EDIT: After more investigation, I observed there's a trigger to generate nextval on a sequence to be inserted into the primary key column. This is the source of the predicament. Hence, following the procedure above would not solve the problem. It lies in the trigger (and/or sequence) on the table. This is solved!
easier to use your .csv as an external table and then go
create table your_table_temp as select * from external table
examine the data in the new temp table to ensure you know what range of primary keys is present
do a merge into the new table
samples from here and here
CREATE TABLE countries_ext (
country_code VARCHAR2(5),
country_name VARCHAR2(50),
country_language VARCHAR2(50)
)
ORGANIZATION EXTERNAL (
TYPE ORACLE_LOADER
DEFAULT DIRECTORY ext_tab_data
ACCESS PARAMETERS (
RECORDS DELIMITED BY NEWLINE
FIELDS TERMINATED BY ','
MISSING FIELD VALUES ARE NULL
(
country_code CHAR(5),
country_name CHAR(50),
country_language CHAR(50)
)
)
LOCATION ('Countries1.txt','Countries2.txt')
)
PARALLEL 5
REJECT LIMIT UNLIMITED;
and the merge
MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
Edit: after you have merged the data you can drop the temp table and the result is your previous table with the old data and the new data together
Edit you mention " During imports, the primary key column does not insert from the file, but auto-increments". This can only happen when there is a trigger on the table, likely, Before insert on each row. Disable the trigger and then do your import. Re-enable the trigger after committing your inserts.
I used the following procedure to solve it:
drop trigger trigger_name
Imported the table data into target table
drop sequence sequence_name
CREATE SEQUENCE SEQ_NAME INCREMENT BY 1 START WITH start_index_for_next_val MAXVALUE max_val MINVALUE 1 NOCYCLECACHE 20 NOORDER
CREATE OR REPLACE TRIGGER "schema_name"."trigger_name"
before insert on target_table
for each row
begin
select seq_name.nextval
into :new.unique_column_name
from dual;
end;

Duplicate key error using nvarchar when adding new row with same number but leading 0

I want to insert a row into a table where in the primary key column I have a value of 3719. However, in the same table I want to add details with 03719 but I am getting an error:
The duplicate key value is (3719).
The datatype of that column is nvarchar.
I think your problem arises from the fact that you forgot to wrap the string value to be inserted in single quotes, so it is treated like a number, which is auto-converted to nvarchar.
INSERT INTO Table (Column) VALUES (03719)
is equivalent to
INSERT INTO Table (Column) VALUES (3719)
The value (because of the column type) is then converted to the string '3719'. Of course you then get a duplicate key error.
Check the quotes. If you're calling this from an application, use parameterized queries!
Correct statement to insert the records is like
Create table test (id nvarchar(25) primary key, name varchar(20))
insert into test values('111','hello')
insert into test values('0111','hello')
select * from test
You're forgetting to put the quotes.
If you do not put the quotes, you will get the below kind of error
Violation of PRIMARY KEY constraint 'PK__test__3213E83F2C904DEB'.
Cannot insert duplicate key in object 'dbo.test'. The duplicate key value is (111).

Update value on insert into table in SQL Server

I am working with SQL Server - on inserting into a table, I have a unique constraint on a table column id. There is a possibility that when inserting, the value going into the id column is 0. This will cause an error.
Is it possible to update this id to another value during the insert if the id value is 0? This is to prevent the error and to give it a valid value.
Possibly a trigger?
A trigger is one way, but you may want to use a filtered index (CREATE UNIQUE INDEX, not as a table constraint) to ignore zero value. This way, you don't have to worry about what value to put there
Alternatively, if you want to populate it from another column, you can have a computed column with a unique constraint.
ALTER TABLE whatever
ADD ComputedUniqueCol = CASE WHEN Id = 0 THEN OtherCol ELSE Id END
If that's your primary key you can specify it as IDENTITY. Then it should generate a value for itself based on seed and increment (the default is seed=1 and default=1) so you don't have to worry about it.
CREATE TABLE MyTable
(
ID int PRIMARY KEY IDENTITY,
...
)
create an "instead of" trigger and check for the value on the ID.
CREATE trigger checkID
on YOUR_TABLE
instead of insert
as
begin
declare #id int
select #id=id from inserted
if (#id==0) begin
--DO YOUR LOGIC HERE AND THEN INSERT
end else begin
insert into DESTINATION_TABLE (VALUES)
SELECT VALUES FROM INSERTED
end
end

SQL unique index without leading zeros

I have set-up a table using the following SQL script:
CREATE TABLE MY_TABLE (
ID NUMBER NOT NULL,
CODE VARCHAR2(40) NOT NULL,
CONSTRAINT MY_TABLE PRIMARY KEY (ID)
);
CREATE UNIQUE INDEX XUNIQUE_MY_TABLE_CODE ON MY_TABLE (CODE);
The problem is that I need to ensure that CODE does not have a leading zero for its value.
How do I accomplish this in SQL so that a 40-char value without a leading zero is stored?
CODE VARCHAR2 NOT NULL CHECK (VALUE not like '0%')
sorry - slight misread on the original spec
If you can guarantee that all INSERTs and UPDATEs to this table are done through a stored procedure, you could put some code there to check that the data is valid and return an error if not.
P.S. A CHECK CONSTRAINT would be better, except that MySQL doesn't support them.

Autoincrement Primary key in Oracle database

I would like to achieve an identity or auto-incrementing value in a column ala SQL Server:
CREATE TABLE RollingStock
(
Id NUMBER IDENTITY(1,1),
Name Varchar2(80) NOT NULL
);
How can this be done?
As Orbman says, the standard way to do it is with a sequence. What most people also do is couple this with an insert trigger. So, when a row is inserted without an ID, the trigger fires to fill out the ID for you from the sequence.
CREATE SEQUENCE SEQ_ROLLINGSTOCK_ID START WITH 1 INCREMENT BY 1 NOCYCLE;
CREATE OR REPLACE TRIGGER BI_ROLLINGSTOCK
BEFORE INSERT ON ROLLINGSTOCK
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
WHEN (NEW.ID IS NULL)
BEGIN
select SEQ_ROLLINGSTOCK_ID.NEXTVAL
INTO :NEW.ID from dual;
END;
This is one of the few cases where it makes sense to use a trigger in Oracle.
If you really don't care what the primary key holds, you can use a RAW type for the primary key column which holds a system-generated guid in binary form.
CREATE TABLE RollingStock
(
ID RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
NAME VARCHAR2(80 CHAR) NOT NULL
);