Adding a computed column that uses MAX - sql

I need to create a sequential number column for record number proposes
I am OK with losing sequence if I delete a row from the middle of the table
For example
1
2
3
If I delete 2, I am ok with new column been 4.
I tried to alter my table to
alter table [dbo].[mytable]
add [record_seq] as (MAX(record_seq) + 1)
but I am getting An aggregate may not appear in a computed column expression or check constraint.
Which is a bit confusing? do I need to specify an initial value? is there a better way?

If you're looking to allocate a sequence number even in cases where the table doesn't get a record inserted, I would handle it in the process responsible for performing those inserts. Create another table, in this table keep track of the max identity value of that sequence. Each time you want to perform an insert, reserve the sequence number you want by updating that table first. If you rely on selecting the max existing value, you could be at risk of multiple sessions getting the same "new" sequence number before inserting. Even if the insert fails, you will have incremented that control table so nothing else uses that value that has been reserved.

Its not supported in MsSql. You can use identity column:
ALTER TABLE [dbo].[mytable]
ADD [record_seq] INT IDENTITY
Or use trigger to update your seq column after insert and/or delete

Related

In SQL, how to populate number in sequence in column without alter the table structure?

populating number in a sequence for a column without altering table structure--need a query
if you don't want to change or alter the database table structure, you have limited solutions actually.
First option might be using a sequence object
create sequence mySequence increment by 1;
After you have a sequence object, you can read from this sequence whenever you need this field value
select mySequence.nextval from dummy;
Unfortunately, each read will increment the current value of the sequence.
This means if you read but did not insert the value into the table, next time you insert a new row there will be a gap in your table column.
Or if you insert two rows from two different executions, one might read the sequence first but insert value later than the other thread; then the sequence will be like 11,12,14,13,15
Second option is creating a database table trigger AFTER INSERT statement.
Then you can the max value from table column (or can store in a separate table) or from sequence, and update the column field with this sequence data

Unique sequence for a column in oracle table

I am trying to load a table where i have a PK column called E_id. I want to generate a unique ID for this column every time a row is loaded into this table at informatica level. But i want this e_id column to generate a unique value at table level. Can i achieve this by writing a query to this column at table create script itself?
Currently i tried this method of defaulting the value with this
e_id NUMBER DEFAULT TO_NUMBER(TO_CHAR(SYSTIMESTAMP, 'YYYYMMDDHH24MISSFF9')) NOT NULL
Although at times i am getting the same value for two records.
Can someone help how to go about this?
TIA.
one of the most common way to do this is using sequences
1 create sequence
2 before insert row trigger that will populate value into the pk column
create sequence GSEQUENCE
minvalue 1000
maxvalue 99999999999999999
start with 93581
increment by 1
cache 20;
CREATE OR REPLACE TRIGGER BI_DOCUMENTS
BEFORE INSERT
on DOCUMENTS
for each row
declare numrows INTEGER;
begin
select gsequence.nextval
into :new.id_DOCUMENT
from dual;
end;
/
If you are using 12c the easiest way is to use an IDENTITY column. Oracle will automatically generate a unique value for the column whenever you insert a record.
In prior versions you can define a sequence and generate it via a trigger or reference it directly in the insert statement.
You mention Informatica. Its a long time since I used it but I seem to remember there being a simple way to generate a unique ID using Informatica too.
You can use Globally Unique ID (GUID) which is unique for all practice purpose. Lot of systems use GUID to generate unique id.
select sys_guid() from dual
Mote into here
While GUID gives truly random unique ids, you can always use Oracle sequence if you need sequential unique values.
Oracle doesn't have "auto increment" columns, but you can achive similar results by a trigger.
EDIT: You can refer this link too How to generate a GUID in Oracle?

Filling incremental unqiue values for a newly created PK

I currently have a table with many rows, but no PK at all. I now require to have a unique, non-null, > 0 PK for every row.
I'm created the column for PK, but how I can I quickly fill in the column with an incremental value starting from 1?
Any method, a single SQL line, or a SQL line to be executed as many times as are rows are good enough for me.
Something like
update sometable set newkeyfield = Row_Number() Over();
should do not a DB2 bloke, but should be close.
Try using a DB2 Sequence object. They are designed for creating unique sequences of numbers. Pick your data type.
CREATE SEQUENCE mySeq as int;
You retrieve and increment the sequence in one step, using a sequence reference
NEXT VALUE FOR mySeq
You expression can use this in an INSERT, UPDATE, or MERGE, or most places you can use an expression.

Auto Increment feature of SQL Server

I have created a table named as ABC. It has three columns which are as follows:-
The column number_pk (int) is the primary key of my table in which I have made the auto increment feature on for that column.
Now I have deleted two rows from that table say Number_pk= 5 and Number_pk =6.
The table which I get now is like this:-
Now if I again enter two new rows in this table with the same value I get the two new Number_pk starting from 7 and 8 i.e,
My question is that what is the logic behind this since I have deleted the two rows from the table. I know that a simple answer is because I have set the auto increment on for the primary key of my table. But I want to know is there any way that I can insert the two new entries starting from the last Number_pk without changing the design of my table?
And how the SQL Server manage this record since I have deleted the rows from the database??
The logic is guaranteeing that the generated numbers are unique. An ID field does not neccessarily have to have a meaning, but rather is most often used to identify a unique record, thus making it easier to perform operations on it.
If your database is designed properly, the deleted ID numbers would not have been possible to delete if they were referenced by any other tables in a foreign key relationship, thus preventing records from being orphaned in that way.
If you absolutely want to have entries sequences, you could consider issuing a RESEED, but as suggested, it would not really give you much advantages.
The identity record is "managed" because SQL Server will keep track of which numbers have been issued, regardless of whether they are still present or not.
Should you ever want to delete all records from a table, there are two ways to do so (provided no foreign key relatsons exist):
DELETE FROM Table
DELETE just removes the records, but the next INSERTED value will continue where the ID numbering left of.
TRUNCATE TABLE
TRUNCATE will actually RESEED the table, thus guaranteeing it starts again at the value you originally specified (most likely 1).
Although you should not do this until their is a specific requirement.
1.) Get the max id:
Declare #id int
Select #id = Max(Number_pk) From ABC
SET #id = #id + 1;
2.) And reset the Identity Column:
DBCC CHECKIDENT('ABC', RESEED, #id)
DBCC CHECKIDENT (Transact-SQL)

SQL Server concurrency

I asked two questions at once in my last thread, and the first has been answered. I decided to mark the original thread as answered and repost the second question here. Link to original thread if anyone wants it:
Handling SQL Server concurrency issues
Suppose I have a table with a field which holds foreign keys for a second table. Initially records in the first table do not have a corresponding record in the second, so I store NULL in that field. Now at some point a user runs an operation which will generate a record in the second table and have the first table link to it. If two users simultaneously try to generate the record, a single record should be created and linked to, and the other user receives a message saying the record already exists. How do I ensure that duplicates are not created in a concurrent environment?
The steps I need to carry out are:
1) Look up x number of records in table A
2) Perform some business logic that prepares a single row which is inserted into table B
3) Update the records selected in step 1) to point to the newly created record in table B
I can use scope_identity() to retrieve the primary key of the newly created record in table B, so I don't need to worry about the new record being lost due to simultaneous transactions. However I need to eliminate the possibility of concurrently executing processes resulting in a duplicate record in table B being created.
In SQL Server 2008, this can be handled with a filtered unique index:
CREATE UNIQUE INDEX ix_MyIndexName ON MyTable (FKField) WHERE FkField IS NOT NULL
This will require all non-null values be unique, and the database will enforce it for you.
The 2005 way of simulating a unique filtered index for constraint purposes is
CREATE VIEW dbo.EnforceUnique
WITH SCHEMABINDING
AS
SELECT FkField
FROM dbo.TableB
WHERE FkField IS NOT NULL
GO
CREATE UNIQUE CLUSTERED INDEX ix ON dbo.EnforceUnique(FkField)
Connections that update the base table will need to have the correct SET options but unless you are using non default options this will be the case anyway in SQL Server 2005 (ARITH_ABORT used to be the problem one in 2000)
Using a computed column
ALTER TABLE MyTable ADD
OneNonNullOnly AS ISNULL(FkField, -PkField)
CREATE UNIQUE INDEX ix_OneNullOnly ON MyTable (OneNonNullOnly);
Assumes:
FkField is numeric
no clash of FkField and -PkField values
Decided to go with the following:
1) Begin transaction
2) UPDATE tableA SET foreignKey = -1 OUTPUT inserted.id INTO #tempTable
FROM (business logic)
WHERE foreignKey is null
3) If ##rowcount > 0 Then
3a) Create record in table 2.
3b) Capture ID of newly created record using scope_identity()
3c) UPDATE tableA set foreignKey = IdOfNewRecord FROM tableA INNER JOIN #tempTable ON tableA.id = tempTable.id
Since I write junk into the foreign key field in step 2), those rows are locked and no concurrent transactions will touch them. The first transaction is free to create the record. After the transaction is committed, the blocked transaction will execute the update query, but won't capture any of the original rows due to the WHERE clause only considering NULL foreignKey fields. If no rows are returned (##rowcount = 0), the current transaction exits without creating the record in table B, and returns some sort of error message to the client. (e.g. Error: Record already exists)