Creating my Custom Unique Key - sql

I have a table in my SQL Server. Currently I am using the identity column to uniquely identify each record but my changing needs required a unique key generated in a certain format (as specified by my client). I have tried to generate the unique key from my application by appending a unique integer (that is incremented on every insert) to the format specified my client is not satisfied with my current solution.
It would be great if I can be directed to a better technique to solve my problem rather then my current solution.
The format is like:
PRN-YEAR-MyAppGeneratedInt

Basically, keep the current identity column. That is the best way for you to identify and manage rows in the table.
If the client needs another unique key, then add it. Presumably, it will be a string (given that it has a "format"). You can possibly create the key as a generated column. Alternatively, you may need to use a trigger to calculate it.
In general, integers are better for identity columns, even if end users never see them. Here are some advantages:
They encode the ordering of row insertion in the database. You can, for instance, get the last inserted row.
They are more efficient for foreign key references (because numbers are fixed-length and generally shorter than strings).
They make it possible to directly address a row, when data needs to be fixed.

You can create a SEQUENCE to serve your purpose which were introduced in SQL Server 2012. A real detailed explanation about SEQUENCE can be found here.
Hope this helps :)
As per you specified in the comments the format let me also give you an example that how you can solve your problem using a sequence:
First create a sequence like:
CREATE SEQUENCE SeqName
AS int
START WITH 1
INCREMENT BY 1
CYCLE
CACHE
Next you can use this sequence to generate your desired unique key in you app program.
Get the next value for sequence "SELECT NEXT VALUE FOR SeqName;"
Create a string using the value like :String key= "PRN"+year+SeqValue;
Finally store this string as your unique key in your Insert statement.
You can write the application code as per you need :)

You could create a Computed Column and just append the identity
('Custom_'+CONVERT(varchar(10),iden))

Related

Confusing t-sql exam answer about sequence or uniqueidentifier

I found a t-sql question and its answer. It is too confusing. I could use a little help.
The question is:
You develop a database application. You create four tables. Each table stores different categories of products. You create a Primary Key field on each table.
You need to ensure that the following requirements are met:
The fields must use the minimum amount of space.
The fields must be an incrementing series of values.
The values must be unique among the four tables.
What should you do?
A. Create a ROWVERSION column.
B. Create a SEQUENCE object that uses the INTEGER data type.
C. Use the INTEGER data type along with IDENTITY
D. Use the UNIQUEIDENTIFIER data type along with NEWSEQUENTIALID()
E. Create a TIMESTAMP column.
The said answer is D. But, I think the more suitable answer is B. Because sequence will use less space than GUID and it satisfies all the requirements.
D is a wrong answer, because NEWSEQUENTIALID doesn't guarantee "an incrementing series of values" (second requirement).
NEWSEQUENTIALID()
Creates a GUID that is greater than any GUID
previously generated by this function on a specified computer since
Windows was started. After restarting Windows, the GUID can start
again from a lower range, but is still globally unique.
I'd say that B (sequence) is the correct answer. At least, you can use a sequence to fulfil all three requirements, if you don't restart/recycle it manually. I think it is the easiest way to meet all three requirements.
Between the choices provided D B is the correct answer, since it meets all requirements:
ROWVERSION is a bad choice for a primary key, as stated in MSDN:
Every time that a row with a rowversion column is modified or inserted, the incremented database rowversion value is inserted in the rowversion column. This property makes a rowversion column a poor candidate for keys, especially primary keys. Any update made to the row changes the rowversion value and, therefore, changes the key value. If the column is in a primary key, the old key value is no longer valid, and foreign keys referencing the old value are no longer valid.
TIMESTAMP is deprecated, as stated in that same page:
The timestamp syntax is deprecated. This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature.
An IDENTITY column does not guarantee uniqueness, unless all it's values are only ever generated automatically (you can use SET IDENTITY_INSERT to insert values manually), nor does it guarantee uniqueness between tables for any value.
A GUID is practically guaranteed to be unique per system, so if a guid is the primary key for all 4 tables it ensures uniqueness for all tables. the one requirement it doesn't fulfill is storage size - It's storage size is quadruple that of int (16 bytes instead of 4).
A SEQUENCE, when is not declared as recycle, guarantee uniqueness, and has the lowest storage size.
The sequence of numeric values is generated in an ascending or descending order at a defined interval and can be configured to restart (cycle) when exhausted.
However,
I would actually probably choose a different option all together - create a base table with a single identity column and link it with a 1:1 relationship with all other categories. then use an instead of insert trigger for all categories tables that will first insert a record to the base table and then use scope_identity() to get the value and insert it as the primary key for the category table.
This will enforce uniqueness as well as make it possible to use a single foreign key reference between the categories and products.
The issue has been discussed extensively in the past, in general:
http://blog.codinghorror.com/primary-keys-ids-versus-guids/
The constraint #3 is why a SEQUENCE could run into issues as there is a higher risk of collision/lowered number of possible rows in each table.

How to modify the value of a primary key?

I want to modify the primary key integer of all rows in a table. My goal is to subtract a specific number from the pk and then reset it.
Is that possible? Pseudocode:
update mytable set id = id-100;
It is possible, but it is never a good idea. A primary key is there for one purpose only, to identify a row uniquely; once you try to make it serve other purposes, such as being a user-visible sequence number, then you will have problems. In systems that use composite keys that contain business information then there is always nasty code to change key information when it turns out the business information needs to change, a significant part of the argument for using artificial keys is to eliminate the need for this kind of error-prone data-munging. Use a separate column for user-visible sequence numbers and don't mix this concern with that of identifying the row uniquely.
OK I found my error: the number has to be wrapped in single quotes:
update mytable set id = id - '100' ;

how to avoid duplicates for unique Id's with timestamp

Hi I have a situation like i am inserting a unique value into Data Base along with primary key
by generating in java code. This unique Id has time stamp Ex:'BatchID16Jul1411111111'. where it is extended up to milliseconds.Now if two users hit at same time same unique ids are generated.
Is there any way to make this times tamp unique even it is called at same time.
Is it possible by getting auto increment number from DB.
Can any one suggest me solution for this situation.
Thanks in advance
Mahesh
Yes, it is possible to get an auto-incremented number from the database. The exact syntax depends on the database. These typically use one of three methods:
An auto-increment declaration in the create table statement;
An identity declaration in the create table statement; or,
A sequence assigned as a default value to the primary key column.
Note, though, that the auto-incremented number will not have any meaning. So, you will need a separate column for the 'BatchId' and for the date time.

Rails & Postgresql create a field that auto increments from 1

I'm looking to create a field called id_visual in my table orders which starts at 1 and auto increments from there. I could create a method in my model to do it but I thought there must be a better more foolproof way. Any ideas?
From what I can tell, you want a secondary id based on the primary id? The identity key can only be table based and can not be dependent on another key. You will have to do this in code and then save it to a new field on before_create. The easiest way to do this is for each order that you want to id, get the count of all orders less than or equal to the one you are working with based on whatever the primary key is. Its a simple one query calculation.
This is something your database should be providing at some level, either in a transaction or with some other locking.
Take a look at this question for some ways to get postgres configured to auto-increment a column:
PostgreSQL Autoincrement

identity column in Sql server

Why does Sql server doesn't allow more than one IDENTITY column in a table?? Any specific reasons.
Why would you need it? SQL Server keeps track of a single value (current identity value) for each table with IDENTITY column so it can have just one identity column per table.
An Identity column is a column ( also known as a field ) in a database table that :-
Uniquely identifies every row in the table
Is made up of values generated by the database
This is much like an AutoNumber field in Microsoft Access or a sequence in Oracle.
An identity column differs from a primary key in that its values are managed by the server and ( except in rare cases ) can't be modified. In many cases an identity column is used as a primary key, however this is not always the case.
SQL server uses the identity column as the key value to refer to a particular row. So only a single identity column can be created. Also if no identity columns are explicitly stated, Sql server internally stores a separate column which contains key value for each row. As stated if you want more than one column to be having unique value, you can make use of UNIQUE keyword.
The SQL Server stores the identity in an internal table, using the id of the table as it's key. So it's impossible for the SQL Server to have more than one Identity column per table.
Because MS realized that better than 80% of users would only want one auto-increment column per table and the work-around to have a second (or more) is simple enough i.e. create an IDENTITY with seed = 1, increment = 1 then a calculated column multiplying the auto-generated value by a factor to change the increment and adding an offset to change the seed.
Yes , Sequences allow more than one identity like columns in atable , but there are some issues here . In a typical development scenario i have seen developers manually inserting valid values in a column (which is suppose to be inserted through sequence) . Later on when a sequence try inserting value in to the table , it may fail due to unique key violation.
Also , in a multi developer / multi vendor scenario, developers might use the same sequence for more than one table (as sequences are not linked to tables) . This might lead to missing values in one of the table . ie tableA might get the value 1 while tableB might use value 2 and tableA will get 3. This means that tableA will have 1 and 3 (missing 2).
Apart from this , there is another scenario where you have a table which is truncated every day . Since Sequences are not having any link with table , the truncated table will continue to use the Seq.NextVal again (unless you manually reset the sequence) leading to missing values or even more dangerous arthmetic overflow error after sometime.
Owing to above reason , i feel that both Oracle sequences and SQL server identity column are good for their purposes. I would prefer oracle implementing the concept of Identity column and SQL Server implementing the sequence concept so that developers can implement either of the two as per their requirement.
The whole purpose of an identity column is that it will contain a unique value for each row in the table. So why would you need more than one of them in any given table?
Perhaps you need to clarify your question, if you have a real need for more than one.
An identity column is used to uniquely identify a single row of a table. If you want other columns to be unique, you can create a UNIQUE index for each "identity" column that you may need.
I've always seen this as an arbitrary and bad limitation for SQL Server. Yes, you only want one identity column to actually identify a row, but there are valid reasons why you would want the database to auto-generate a number for more than one field in the database.
That's the nice thing about sequences in Oracle. They're not tied to a table. You can use several different sequences to populate as many fields as you like in the same table. You could also have more than one table share the same sequence, although that's probably a really bad decision. But the point is you could. It's more granular and gives you more flexibility.
The bad thing about sequences is that you have to write code to actually increment them, whether it's in your insert statement or in an on-insert trigger on the table. The nice thing about SQL Server identity is that all you have to do is change a property or add a keyword to your table creation and you're done.