Forcing data entry in order - sql

I have a sql server database with ms access frontend.
I want to force data to be entered in a particular table in order.
eg I can only enter id = 2 after id = 1 has been added and I can only add id = 3 after 2 and 1 have been added.
What is the best way to enforce this? Do I need a restriction added to the access frontend or do I need to add a trigger or similar to the sql table?

i agree with #Vamsi Pamula, You can do that. But, however if you want to do only what your are looking for then :
First of all, When user tries to enter an new record, track the New ID Given Suppose 10 for now. And, first Query in the database for the Max id before like :
Select isnull(Max(id),0) from YourTable
Suppose the above query returned 8. So, 10 should not be allowed. Now now check :
if (ReturnedValuefromAboveQry + 1 = NEWID) then
msgbox "Allowed."
else
msgbox "Not Allowed."
End If

If you want to do so, keep that id as primary key and set it property as identity (auto increment). You no need to insert that value. Insert the remaining columns and that id will be automatically saved as 1,2 and so on

Related

Oracle : Create session sequence?

I have a table as follows
The table contains my application users and stores their clients. The column User Client ID refers to a foreign key linked to a different table that stores the clients details.
I need another column (User Client Counter) which is a just a counter of the clients of each user. I need it to start from 1 and goes up for each individual application user.
For the moment I'm populating this by counting the number of clients for each user + 1 before inserting a new row in the table :
select count(*) + 1 into MyVariable from Mytable where UserClientId = Something
Then I use MyVariable in the column User Client Counter
This methods works quite well, but in case the user is connected from two different sessions, the query may produce a wrong number of counts... in addition to that the performance may be bad in case of big tables...
Is there anyway better way to replace such process by using sequences ?
I've been looking to session sequences but there are reset after the end of each session.
(This column is a business need and cannot be replaced by something like rownumber in restitution queries. Since every client has to keep always the same identifier for the application user)
Thank you in advance.
Cheers,
I think you can just create a unique index on the app user and the running number:
create unique index idx on mytable (app_user_id, num);
And then insert with max + 1:
insert into mytable (app_user_id, client_id, num)
values
(
:app_user_id,
:client_id,
coalesce((select max(num) + 1 from mytable where app_user_id = :app_user_id), 1)
);
For this sort of requirement to be safe you will need to be able to lock rows at the right level so that you don't have two sessions that think the they are allowed to use the same value. The impact of this is that while one session is inserting a row for the 'Company X' user, another session will wait for the first user to commit if they're also trying to insert a row for 'Company X'.
This is super easy when you just have a table that stores information at the right level.
You can have a table of your users with a counter column which starts at 0.
MY_APPLICATION_USER CLIENT_COUNTER
-------------------------------------------------- --------------
Company X 1
Company Y 3
Company Z 1
As you insert rows into your main table, you update this table first setting the client_counter to be client_counter + 1 (you do this as one insert statement, no risky select then update!), then you return the updated value into your value for the client_id. This can all be done with a simple trigger.
create or replace trigger app_clients_ins
before insert
on app_clients
for each row
declare
begin
update app_users
set client_counter = client_counter + 1
where my_application_user = :new.my_application_user
return client_counter into :new.user_client_number;
end;
/
Of course, like any sequence if you delete a row it's not going to allow your next insert to fill that gap.
(db<>fiddle https://dbfiddle.uk/?rdbms=oracle_18&fiddle=7f1b4f4b6316d5983b921cae7b89317a )
if you want to have unique values to be inserted and there are chances that multiple users can insert rows into the same table at the same time then it is better to user Oracle Sequence.
CREATE SEQUENCE id_seq INCREMENT BY 1;
INSERT INTO Mytable(id) VALUES (id_seq.nextval);
In you case I think you want different sequence created for each Customer, How many different Customers you have, if you have in 100's then i don't think create sequence will work as you may have to create as many sequence .

Postgres upsert using on conflict - multiple fields in on conflict condition

I'm trying to implement the concept of liking / disliking an item in a postgres db - when the user likes / dislikes something, I want to insert an item into my DB to represent this.
This is my schema:
id | postID | userID | type
1 2 1 like
Now if the user has already liked the item, and now they decide to dislike it - I want to update the type field, from like to dislike.
Similarly, if they've disliked something and now decided to like it, I want to perform the opposite update.
Furthermore, a user can only like / dislike something once - so if the user has liked / disliked the post previously and now decides to like / dislike it again, nothing should happen.
This means I need to implement an upsert statement in postgres, which inserts a new row, if the user has not interacted with the post previously, and updates the type field, if a row with the specified postID + userID + type already exists.
I was looking at doing this using the on conflict syntax -
INSERT INTO table_name(postID,userID,type)
VALUES(2,1,'like')
ON CONFLICT (????) DO UPDATE
SET type = 'like'
but I'm not sure what to pass into the ON CONFLICT section, since the match needs to happen on multiple fields.
I considered setting a unique index on the (postID, userID) fields - something like this:
create unique index idx_1 on table (postID, userID)
The problem is I want to use this DB in the future to store comment information, and a user is allowed to comment on the same post multiple times.
An example would be:
id | postID | userID | type
1 2 1 comment
2 2 1 comment
3 2 1 like
If you want to limit the number of updates to a row, you can use a check constraint and secondary column counting the updates.
alter table t add column num_updates int default 1 check (num_updates <= 2);
Then, if you want to prevent duplicate rows on types other than comment, you can use a filtered unique index:
create unique index unq_table_name_postid_userid
on table_name(postid, userid)
where type <> 'comment';
Then I think you can express the logic using on conflict:
INSERT INTO table_name (postID, userID, type)
VALUES(2, 1, 'like')
ON CONFLICT (postID, userID) DO UPDATE
SET type = 'like',
num_updates = excluded.num_updates + 1;
This allows only one update. You might want more refined logic, such as updating the value only if type changes:
num_update = (excluded.num_updates = num_updates)::int + 1

Update a table and return both the old and new values

Im writing a VB app that is scrubbing some data inside a DB2 database. In a few tables i want to update entire columns. For example an account number column. I am changing all account numbers to start at 1, and increment as I go down the list. Id like to be able to return both the old account number, and the new one so I can generate some kind of report I can reference so I dont lose the original values. Im updating columns as so:
DECLARE #accntnum INT
SET #accntnum = 0
UPDATE accounts
SET #accntnum = accntnum = #accntnum + 1
GO
Is there a way for me to return both the original accntnum and the new one in one table?
DB2 has a really nifty feature where you can select data from a "data change statement". This was tested on DB2 for Linux/Unix/Windows, but I think that it should also work on at least DB2 for z/OS.
For your numbering, you might considering creating a sequence, as well. Then your update would be something like:
CREATE SEQUENCE acct_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO CYCLE
CACHE 24
;
SELECT accntnum AS new_acct, old_acct
FROM FINAL TABLE (
UPDATE accounts INCLUDE(old_acct INT)
SET accntnum = NEXT VALUE FOR acct_seq, old_acct = accntnum
)
ORDER BY old_acct;
The INCLUDE part creates a new column in the resulting table with the name and the data type specified, and then you can set the value in the update statement as you would any other field.
A possible solution is to add an additional column (let's call it oldaccntnum) and assign old values to that column as you do your update.
Then drop it when you no longer need it.
Here's what I'd do:
-- create a new table to track the changes.
- with columns identifying a unique key, old-vale, new-value, timestamp
-- create a trigger on the accounts table
to write the old and new values to the new table.
But, not knowing all the conditions, it may not be worth the trouble.

How to generate unique sequence id in SQL Server with multiple transactions

I have an issue with SQL Server ..
What I want is to generate unique id for every transaction which is pre transaction prior to use commit transactions
Scenario :
There are 10 computers when they will open their web browser then each each browser will display series of unique id's on them like comp 1 will display 101 comp 2 will display 102 and comp 3 will generate 103 ....and so on !
I want to handle this on database end can you guys help me with this
Thanks in advance, guys ....
Create a table with single autoincrement column.
When you need another unique id - just insert null into that column and retrieve last insert id.
For oracle - create a sequence and use SELECT sequence_name.nextval FROM DUAL`
For sql server - create a sequence and fetch it with NEXT VALUE FOR
In SQL Server to generate truly unique ID I suggest using GUID, e.g.:
DECLARE #UniqueID uniqueidentifier
SET #UniqueID = NEWID()

How to set up manually the next value of auto_increment?

I added some rows into the table manually and also I set up the ID (auto_increment) manually. Now when I try to add new row through my app into DB table, to DB table I am getting the error , that the created ID value already exist.
How can I set manually the next ID value (for example, in table I have to IDs, so how to tell to PostgreSQL, that the next ID should be counted since the number 3)?
http://www.postgresql.org/docs/current/static/functions-sequence.html
select setval('sequence-name', <new-value>);
You can get the sequence name from the the table definition:
id | integer | not null default nextval('id_seq'::regclass)
In this case the sequence is named 'id_seq'
Edit (10x to #Glenn):
SELECT setval('id_seq', max(id)) FROM table;
I think there is a simpler way:
ALTER SEQUENCE "seq_product_id" RESTART WITH 10