oracle stop select duplicated value - oracle-sqldeveloper

I am trying to insert data in my table from another which has two column (employee number) and (branch),
and whenever new data is inserted the employee last number value is increased,
my code is working fine but if the there are more than one employee inserted at the same time they will have duplicated value.
for example, if I inserted the data with branch number is 100 the employee will have number 101, and if the branch number is 200 the employee will have number 201 etc.
but if data inserted for two employees both have same branch for example number 200 both of them will have number 201, but I want the first one to have 201 and the second one to have 202,
I hope you get what I mean, any help will be appreciated.
here is my code:
insert into emp_table_1
Emp_Name_1,
Emp_Branch_1,
Emp_number_1
Select Emp_Name_2 ,
Emp_Branch_2,
Case emp_branch
When '100' Then (Select Max(Emp_number_1)+1 From emp_table_1 Where Branch_Cd=100)
When '200' Then (Select Max(Emp_number_1)+1 From emp_table_1 Where Branch_Cd=200)
End As Emp_number_2
From emp_table_2

Don't try to have sequential numbers for each branch and don't try to use MAX to find the next number in the sequence.
Use a sequence (that is what they are designed for).
CREATE SEQUENCE employee_id__seq;
Then you can use:
insert into emp_table_1 (Emp_Name_1, Emp_Branch_1, Emp_number_1)
Select Emp_Name_2 ,
Emp_Branch_2,
employee_id__seq.NEXTVAL
From emp_table_2
Then each employee will have a unique number (which you can use as a primary key) and you will not get concurrency issues if multiple people try to create new users at the same time.
Or, from Oracle 12, you could use an identity column in your table:
CREATE TABLE emp_table_1(
emp_name_1 VARCHAR2(200),
emp_branch_1 CONSTRAINT emp_table_1__branch__fk REFERENCES branch_table (branch_id),
emp_number_1 NUMBER(8,0)
GENERATED ALWAYS AS IDENTITY
CONSTRAINT emp_table_1__number__pk PRIMARY KEY
);
Then your query is simply:
insert into emp_table_1 (Emp_Name_1, Emp_Branch_1)
Select Emp_Name_2 ,
Emp_Branch_2
From emp_table_2
And the identity column will be auto-generated.

Related

Data Warehouse - unique constraint on dimension tables, is such design possible?

The database used is postgresql.
Suppose I have dimension table dim_orders with fields describing order line (one order number can has many order line, different on item name):
order_id (auto-increment primary key)
order_number
order_status (NEW, PAID, ORDERED, ...)
item_name
...
Then I have ETL process that runs hourly. The data source is from sales database. The problem is, we have order_line_status field, which can change hour-to-hour (e.g. one cycle will be NEW > PAID > ORDERED > DELIVERED > CLOSED) on the data source. And this order status can be different for each order. For example, when order X has line X1 (item : chocolate) and line X2 (item : coffee), the X1 chocolate might already DELIVERED, but X2 coffee still on ORDERED.
My fact_sales table is something like this:
sales_id (auto-increment primary key)
order_id (foreign key to dim_orders), which basically the order line : chocolate or coffee on sample above
quantity (taken from sales data)
discount_amount (taken from sales data)
...
To maintain speed, I'd like to avoid network / SQL call everytime the ETL process runs.
This is because the network sometimes full and quite slow.
Right now, every ETL process one sales data, I query from dim_orders :
**existing_order_id = "SELECT order_id FROM dim_orders WHERE order_number = [staging_data.order_number] AND item_name = [staging_data.item_name]"**
if existing_order_id found then:
- update dim_orders set order_status = new order status from staging data (it might changed or not since last hour ETL)
- update fact_sales, using data on staging table
else:
- insert into dim_sales, get new order_id. Something like (INSERT INTO dim_orders ... RETURNING order_id)
- insert into fact_sales, using order_id
The problem is on the bold statement, where I always query for existing order ID. If I have 10k rows, this means 10k select before processing the data. I'm trying to change the dim_orders, using unique key on (order_number, item_name), so instead of select-insert/update, I can have something like this (I think)
A. upsert data from staging_table into dim_orders. If existing (order_number, item_name) match, update the order_status.
B. process the fact table, using returned order id
Since we can get the order id from fact table, query A can be achieved by:
INSERT INTO dim_orders (order_number, item_name, order_status, ...) VALUES (...)
ON CONFLICT(order_number, item_name) DO UPDATE
SET order_status = excluded.order_status
RETURNING order_id
Now, the only problem to do this, I have to add unique constraint on dim_orders where (order_number, item_name) must be unique.
However, this design is rejected, because we never have unique constraint on dimension tables before. But from what I get, the reason is because we never done it before.
So my question is:
is it OK to add unique constraint on star schema (fact / dim tables)? Or it is actually bad by design, why?
In term of data warehouse, is there any other approach for this kind of select-insert/update problem?
Thanks

Prevent two threads from selecting same row ibm db2

I have a situation where I have multiple (potentially hundreds) threads repeating the same task (using a java scheduled executor, if you are curious). This task entails selecting rows of changes (from a table called change) that have not yet been processed (processed changes are kept track in a m:n join table called process_change_rel that keeps track of the process id, record id and status) processing them, then updating back the status.
My question is, how is the best way to prevent two threads from the same process from selecting the same row? Will the below solution (using for update to lock rows ) work? If not, please suggest a working solution
Create table change(
—id , autogenerated pk
—other fields
)
Create table change_process_rel(
—change id (pk of change table)
—process id (pk of process table)
—status)
Query I would use is listed below
Select * from
change c
where c.id not in(select changeid from change_process_rel with cs) for update
Please let me know if this would work
You have to "lock" a row which you are going to process somehow. Such a "locking" should be concurrent of course with minimum conflicts / errors.
One way is as follows:
Create table change
(
id int not null generated always as identity
, v varchar(10)
) in userspace1;
insert into change (v) values '1', '2', '3';
Create table change_process_rel
(
id int not null
, pid int not null
, status int not null
) in userspace1;
create unique index change_process_rel1 on change_process_rel(id);
Now you should be able to run the same statement from multiple concurrent sessions:
SELECT ID
FROM NEW TABLE
(
insert into change_process_rel (id, pid, status)
select c.id, mon_get_application_handle(), 1
from change c
where not exists (select 1 from change_process_rel r where r.id = c.id)
fetch first 1 row only
with ur
);
Every such a statement inserts 1 or 0 rows into the change_process_rel table, which is used here as a "lock" table. The corresponding ID from change is returned, and you may proceed with processing of the corresponding event in the same transaction.
If the transaction completes successfully, then the row inserted into the change_process_rel table is saved, so, the corresponding id from change may be considered as processed. If the transaction fails, the corresponding "lock" row from change_process_rel disappears, and this row may be processed later by this or another application.
The problem of this method is, that when both tables become large enough, such a sub-select may not work as quick as previously.
Another method is to use Evaluate uncommitted data through lock deferral.
It requires to place the status column into the change table.
Unfortunately, Db2 for LUW doesn't have SKIP LOCKED functionality, which might help with such a sort of algorithms.
If, let's say, status=0 is "not processed", and status<>0 is some processing / processed status, then after setting these DB2_EVALUNCOMMITTED and DB2_SKIP* registry variables and restart the instance, you may "catch" the next ID for processing with the following statement.
SELECT ID
FROM NEW TABLE
(
update
(
select id, status
from change
where status=0
fetch first 1 row only
)
set status=1
);
Once you get it, you may do further processing of this ID in the same transaction as previously.
It's good to create an index for performance:
create index change1 on change(status);
and may be set this table as volatile or collect distribution statistics on this column in addition to regular statistics on table and its indexes periodically.
Note that such a registry variables setting has global effect, and you should keep it in mind...

Primary key duplicate in a table-valued parameter in stored procedure

I am using following code to insert date by Table Valued Parameter in my SP. Actually it works when one record exists in my TVP but when it has more than one record it raises the following error :
'Violation of Primary key constraint 'PK_ReceivedCash''. Cannot insert duplicate key in object 'Banking.ReceivedCash'. The statement has been terminated.
insert into banking.receivedcash(ReceivedCashID,Date,Time)
select (select isnull(Max(ReceivedCashID),0)+1 from Banking.ReceivedCash),t.Date,t.Time from #TVPCash as t
Your query is indeed flawed if there is more than one row in #TVPCash. The query to retrieve the maximum ReceivedCashID is a constant, which is then used for each row in #TVPCash to insert into Banking.ReceivedCash.
I strongly suggest finding alternatives rather than doing it this way. Multiple users might run this query and retrieve the same maximum. If you insist on keeping the query as it is, try running the following:
insert into banking.receivedcash(
ReceivedCashID,
Date,
Time
)
select
(select isnull(Max(ReceivedCashID),0) from Banking.ReceivedCash)+
ROW_NUMBER() OVER(ORDER BY t.Date,t.Time),
t.Date,
t.Time
from
#TVPCash as t
This uses ROW_NUMBER to count the row number in #TVPCash and adds this to the maximum ReceivedCashID of Banking.ReceivedCash.

On auto increment in Oracle10g for ID, if a row is deleted, will the new row start with a new sequence or continue from the deleted sequence

I have implemented auto increment on my table in oracle using sequence and trigger.
The first two records entered had IDs in a consecutive order, but on the entry of the third record, there was a gap. The ID was 8 for it. On deletion of the record and entery of the new record, the ID became 9.
How do I remove the gap and get the ID of the 3rd record as 3 and in consecutive order for next.
If a row is deleted will the new row start with a new sequence or continue from the deleted sequence?
How do I solve this problem?
Please help
Gaps in a sequence are never reused. You should expect gaps anyway, even without deletions, due to caching, rollbacks, RAC etc. You may not even get the sequences in the order you expect if you're using RAC. An ID, particularly an 'auto-incremented' one, is generally a synthetic primary key and the actual value of the key has no intrinsic meaning, it merely has to be unique.
Tom Kyte has a view on this subject, of course.
If gaps were re-used, what would happen if you added three records which got IDs 1, 2 and 3, and then deleted record 2? Would the next inserted record get ID 2 or 4? Even if you filled in the gap (which would mean serialising and basically ignoring the sequence) then the IDs are not in the order they were inserted, so you still can't discern anything from looking at the IDs. You don't know, from the ID, what order they were inserted.
If you really want seamless numbering for display purposes you can ignore the ID value and use a pseudo-column:
select t.column1, t.column2, ...,
row_number() over (order by t.id) as rn
from your_table t;
If you need to track the order they were inserted then add a timestamp field and set that to sys_timestamp in your trigger as well. You could then generate a seamless number in that order instead:
select t.column1, t.column2, ...,
row_number() over (order by t.inserted) as rn
from your_table t;

SQLite - a smart way to remove and add new objects

I have a table in my database and I want for each row in my table to have an unique id and to have the rows named sequently.
For example: I have 10 rows, each has an id - starting from 0, ending at 9. When I remove a row from a table, lets say - row number 5, there occurs a "hole". And afterwards I add more data, but the "hole" is still there.
It is important for me to know exact number of rows and to have at every row data in order to access my table arbitrarily.
There is a way in sqlite to do it? Or do I have to manually manage removing and adding of data?
Thank you in advance,
Ilya.
It may be worth considering whether you really want to do this. Primary keys usually should not change through the lifetime of the row, and you can always find the total number of rows by running:
SELECT COUNT(*) FROM table_name;
That said, the following trigger should "roll down" every ID number whenever a delete creates a hole:
CREATE TRIGGER sequentialize_ids AFTER DELETE ON table_name FOR EACH ROW
BEGIN
UPDATE table_name SET id=id-1 WHERE id > OLD.id;
END;
I tested this on a sample database and it appears to work as advertised. If you have the following table:
id name
1 First
2 Second
3 Third
4 Fourth
And delete where id=2, afterwards the table will be:
id name
1 First
2 Third
3 Fourth
This trigger can take a long time and has very poor scaling properties (it takes longer for each row you delete and each remaining row in the table). On my computer, deleting 15 rows at the beginning of a 1000 row table took 0.26 seconds, but this will certainly be longer on an iPhone.
I strongly suggest that you re-think your design. In my opinion your asking yourself for troubles in the future (e.g. if you create another table and want to have some relations between the tables).
If you want to know the number of rows just use:
SELECT count(*) FROM table_name;
If you want to access rows in the order of id, just define this field using PRIMARY KEY constraint:
CREATE TABLE test (
id INTEGER PRIMARY KEY,
...
);
and get rows using ORDER BY clause with ASC or DESC:
SELECT * FROM table_name ORDER BY id ASC;
Sqlite creates an index for the primary key field, so this query is fast.
I think that you would be interested in reading about LIMIT and OFFSET clauses.
The best source of information is the SQLite documentation.
If you don't want to take Stephen Jennings's very clever but performance-killing approach, just query a little differently. Instead of:
SELECT * FROM mytable WHERE id = ?
Do:
SELECT * FROM mytable ORDER BY id LIMIT 1 OFFSET ?
Note that OFFSET is zero-based, so you may need to subtract 1 from the variable you're indexing in with.
If you want to reclaim deleted row ids the VACUUM command or pragma may be what you seek,
http://www.sqlite.org/faq.html#q12
http://www.sqlite.org/lang_vacuum.html
http://www.sqlite.org/pragma.html#pragma_auto_vacuum