SQL Identity with leading padded zeros - sql

I have marked a column as Identity in my table
create table Identitytest(
number int identity(1,001) not null,
value varchar(500)
)
I need the identity column to be incremented as 001,002,003, etc.
The database shows that it is inserting as 1,2,3, etc.
How can this be done?

As the others have already rightfully pointed out - an INT never has leading zeroes - it just holds the value, that's all (and that's good that way).
If you need some additional formatting, you could always add a computed column to your table, something like:
ALTER TABLE dbo.Identitytest
ADD DisplayNumber AS RIGHT('000' + CAST(number AS VARCHAR(3)) , 3) PERSISTED
This way, your INT IDENTITY will be used as an INT and always contains the numerical value, while DisplayNumber contains 001, 002, ... 014, 015, ..... and so forth - automagically, always up to date.
Since it's a persisted field, it's now part of your table, and you can query on it, and even put an index on it to make queries faster:
SELECT value FROM dbo.IdentityTest WHERE DisplayNumber = '024'
And of course, you could use just about any formatting in the definition of your computed column, so you could also add a prefix or something:
ALTER TABLE dbo.Identitytest
ADD DisplayNumber
AS 'ABC-' + RIGHT('000' + CAST(number AS VARCHAR(3)) , 3) PERSISTED
So in this case, your DisplayNumber would be ABC-001, ABC-002, ... and so on.
You get the best of both worlds - you keep your INT IDENTITY which is numerical and automatically increased by SQL Server, and you can define a display format any way you like and have that available at any time.

If you want to display your number column with leading zeros, just pad it in your SELECT statement. It's a number, it will NOT store with leading zeros as an integer.
SELECT RIGHT('00000' + CAST([number] AS varchar(5)) , 3)
FROM IdentityTest
The 3 is the number of characters you want total in the output display.

If you require both the auto-incrementing number (which can only be a number) and an alphabetic representation of the number, you might consider looking at computed columns.
Here's a few links to get you going:
http://www.mssqltips.com/tip.asp?tip=1682
http://msdn.microsoft.com/en-us/library/ms191250.aspx
http://www.kodyaz.com/articles/sql-server-computed-column-calculated-column-sample.aspx

Why do you need that? As an integer, 001 is the same as 1. If what you want is that for display or other purposes, create another column and do your work there (you may do it as part of a trigger on the table, on insert, that looks at the newly inserted row, and creates the entry in the column appropriately.

i've got a table where i'm storing an integer, but the users want to see it a XXX, even if it has zeroes, so i wrote this code
declare #a int
set #a=1
select replicate('0',3-len(#a))+ cast(#a as varchar(4))

Here is another method:
create table TEST_T (ui int NOT NULL identity, name varchar(10))
insert into TEST_T values ( 'FRED' )
select NAME, ui, RIGHT('0000' + LTRIM(STR(ui)), 4) as ui_T from TEST_T
go
/* NOTE: A view could be created with a calculated column instead of the identity column. */
create view TEST_V as select NAME, RIGHT('0000' + LTRIM(STR(ui)), 4) as ui_V from TEST_T go
go
select * from TEST_V
drop view TEST_V
drop table TEST_T
Not quite as much data duplication(?) as adding a column to the table and no need to specify the column in the select statement.

I need the identity column to be
incremented as 001,002,003, etc.
The database shows that it is
inserting as 1,2,3, etc.
SQL databases store values, not the literals you used to write those values. 002 is 2. Just like 1 + 1 is 2. Would you expect SELECT 1 + 1 to display the string "1 + 1" instead of 2?
If you want the leading zeros to be stored in your column, you have to use a character type. But then you can't use AUTOINCREMENT/IDENTITY.
What you probably really want is something like printf("%03d", number) in program that reads from the database.

Related

Generate a unique value by Increment a column based on another column value

I have to generate a unique code for each row by concatenating 2 values sequentially in SQL server. Eg: H1_123
Once the part2 (i.e 123) reaches 999, I have to increment part1 (i.e H1 to H2 ). So the desired output is H2_001, H2_002... H2_999, H3_001 etc. Please help me with this.
Edit: everytime a new row is inserting this unique code should be generated. The second part I can achieve through a sequencer, but how to increment the first part (H1) when the second part reaches 999?
If any suggestions without using loop will be helpful.
As I allude to in the comment, it seems like you are overly complicating this. You don't want to concatenate 2 values, you just need to do a little arithmetic to get the value you want. Just use a computed column like shown in the below example:
CREATE TABLE dbo.YourTable (ID int IDENTITY(1,1),
YourColumn AS CONCAT('H',(ID + 1000) / 1000, '_', RIGHT(CONCAT('000',ID),3)) PERSISTED);
GO
INSERT INTO dbo.YourTable
DEFAULT VALUES;
GO
INSERT INTO dbo.YourTable
DEFAULT VALUES;
INSERT INTO dbo.YourTable
DEFAULT VALUES;
GO
SELECT *
FROM dbo.YourTable;
GO
DROP TABLE dbo.YourTable
If you need to go from 999 to 001 the you could do the below, which is a little messy:
YourColumn AS CONCAT('H',(ID + ((ID-1) / 999)) / 1000 + 1, '_', RIGHT(CONCAT('000',ID + ((ID-1) / 999)),3)) PERSISTED
db<>fiddle

SQL Server - Reset custom identity column

I have a table with two columns ID and SubDetail. I have created custom identity like 2018XX for the ID columns with 2018 as current year and XX as a number and it will start from "01". I have searched for some topic about "Reset identity field - SQL Server" but It only showed how to reset only number identity field. I'm confused that is there anyway to reset custom identity field.
Here is my SQL query code:
CREATE PROCEDURE spAddSubWareHouse
(#SubDetail VARCHAR(50))
AS
BEGIN
DECLARE #maxDetailID INT
SELECT #maxDetailID = MAX(CAST(RIGHT(ID, 2) AS INT))
FROM SubWareHouse
IF (#maxDetailID IS NULL)
SET #maxDetailID = 1
ELSE
SET #maxDetailID += 1
--insert
INSERT INTO SubWareHouse
VALUES (CAST(YEAR(GETDATE()) AS VARCHAR) + RIGHT('00' + CAST(#maxDetailID AS VARCHAR), 2), #SubDetail)
END
Don't bother doing this. Simply have a numeric identity column defined as:
id int identity(1, 1) primary key
You can then store the year as a separate column, because that appears to be information that you want.
Why do it this way? There are many reasons. First, identity is built into the database. So, identity columns are guaranteed to be unique even when multiple applications are doing inserts at the same time.
Second, integers are more efficient (slightly) for foreign key references.
Third, the locking required to do what you really want is very cumbersome and could significantly slow down your system. Plus, any implementation to prevent duplicates could have a bug -- so why not use the built-in mechanisms?
If you need to get the sequence number for a given year, it is easy enough using row_number():
select row_number() over (partition by year order by id) as year_sequence_number

Create column from other columns in Database

I have a table name: test
ID | Prefix | ACCID
ID's type is INTEGER which is selected from ID_SEQ
Prefix's type is VARCHAR(6)
ACCID is the combination of Prefix + ID
I want to auto-create ACCID when I insert the ID and Prefix value such as
INSERT INTO TEST (PREFIX) VALUES ('A01407V');
and the database store the ACCID as 'A01407V000001'
I create the sequence as
CREATE SEQUENCE ID_SEQ AS INT MAXVALUE 999999 CYCLE;
How to implement SQL statement to produce this result?
Thank you for all solutions and suggestions.
Ps. I use Apache Derby as my SQL Server
As documented in the manual, Derby supports generated columns (since Version 10.5)
The real problem is the formatting of a number with leading zeros as Derby has no function for that.
If you really, really think you need to store a value that can always be determined by the values already stored in the table, you can use something like this:
create table test
(
id integer,
prefix varchar(6),
accid generated always as (prefix||substr('000000', 1, 6 - length(rtrim(char(id))))||rtrim(char(id)))
);
The expression substr('000000', 1, 6 - length(rtrim(char(id))))||rtrim(char(id)) is just a complicated way to format a the ID with leading zeros.
I would highly recommend to not store this value though. It is much cleaner to create a view that shows this value if you do need access to this in SQL.
You can use COMPUTED Column.
Is a computed column that is based on some other column in the table. We can physically save the data of the column/ or not. Table will automatically update the value of this column.
syntax:
columnname AS expression [PERSISTED]
--PERSISTED will make it physically saved, otherwise it will be calculated every time.
We can create indexes on computed columns.
You add, The following in the table CREATE Script
ACCID AS Prefix + CAST(ID AS CHAR(6)) [PERSISTED]

How can I auto-generate complex identifiers and ensure uniqueness?

I've been handed a very specific business requirement, and I'm having trouble translating it to work within our database.
We have multiple departments, who all deal with what we call files. Each file has a unique identifier, but how this identifier is assigned depends on the department that the file is associated with.
Departments ABC, DEF and GHI need the system to provide them with the next identifier following a pattern... while departments JKL and MNO need to be able to specify their own identifiers.
This is further compounded by the fact that the generated file numbers are semi complex. Their file numbers follow the pattern:
[a-z]{3,4}\d{2}-\d{4}
(A 3 or 4 letter prefix that corresponds to the department with two digits corresponding to the year, a dash followed by a four digit generated number - i.e. ABC13-0001)
The part before the dash is easy to generate... the file table has a mandatory foreign key reference to a department table that has the prefix column, and I can grab the year just as easily. it's the part after the dash that I can't seem to work out.
It's a four digit identifier. Each department needs the next generated ID to be as sequential to their department as possible (I say as sequential as possible, as I'm aware that even identity specifications can leave gaps). On top of that, we need to reset it back to 0001 each year. All of that, while ensuring that there are no duplicates, which is the most important part of all of this.
So, we only have one file table that is used by all of these departments. As such, to be able to handle JKL and MNO, I have the FileNumber field set to varchar(12) with a unique constraint. They can type in whatever they need, so long as it's unique. That just leaves me with how to generate the unique file numbers for the other departments.
My first instinct is to give the file table a surrogate identity primary key to make sure that, even if something goes wrong with the generated file number, that each record is guaranteed a unique identifier.
Then I would create a single row table that has two columns per department, one for a number and one for a date. The number would be the last used number for the 4 digit identifier suffix for a given department (as an int), and the date would be when it was assigned. Storing the date would let me check if the year has changed since the last id was pulled so that I can assign 1, instead of lastid + 1.
Then an insert trigger on the file table would generate the file id using:
The foreign key to the department table to get the department prefix
CONVERT(VARCHAR, YEAR( GETDATE() ) % 100) to pull the current two digit year
A select to the above described utility table to get the last id + 1 (or reseting to 1 if the current year differs from the year of the last updated date).
The trigger would finally update the utility table with the last used id and date.
In theory, I think that would work... and the unique constraint on the file id column would prevent an insert where the generated file id already exists. But it feels so brittle, and I can foresee that unique constraint being a double edged sword that would possibly prevent a department from creating a new file should the trigger fail to update the utility table. After all, if it doesn't, then the next time a file number is generated, it would try to use the same generated id, and fail. There must be a better way.
My other thought was to have a table per department with just an identity integer column and non-null date field with a default of (getdate())... and have the trigger on the file table insert a new row, and use that id. It would also be responsible for deleting all rows in the given department id table and reset the identity come the new year. It feels more secure to me, but then I have 5 utility tables (1 per department that auto-generate ids) with up to 9999 records, just to generate an id.
Am I missing something simple? Am I going about this the right way? I just can't help but think that there must be an easier way. Am I right to try to make the SQL server responsible for this, or should I try doing this in the desktop application that I will build on top of this database?
So, I think it's possible you're overcomplicating this. It's also possible I'm misunderstanding the requirements. I don't believe you need separate tables or anything, you just need to check the existing IDs and increment them. SQLFiddle doesn't seem to be working right now, but here's a method I came up with in my local DB:
create table dept_ids (
id varchar(12) primary key
)
insert into dept_ids values('ABC13-0001')
insert into dept_ids values('DEF13-0001')
insert into dept_ids values('GHI13-0001')
insert into dept_ids values('JKL13-0001')
insert into dept_ids values('ABC13-0002')
declare
#dept varchar(4)
, #year varchar(2)
, #prefix varchar(8)
, #new_seq int
set #dept = 'ABC'
select #year = right(cast(DATEPART(yy, getdate()) as varchar(4)), 2)
set #prefix = #dept + #year + '-'
select #new_seq = isnull(right(max(id), 4), 0) + 1 from dept_ids where id like #prefix + '%'
select new_id = #prefix + right(replicate('0', 4) + cast(#new_seq as varchar(4)), 4)
This handles the different departments of course, as well as the year scenario by using getdate() and an ISNULL check. For the departments that can enter their own sequence values, you can just add a null check for that parameter and skip generating this value if it's present.
If I'm oversimplifying, feel free to let me know and I'll adjust.

Is there any editable Auto-Increment besdies IDENTITY?

The reason I need this for is that I made a column on my table called display_order, for now it's smallint and the numbers were pre-determined.
However, when I insert a new record with my software I don't know how to get the highest number in that column and add 1, so I thought about the possibility of an auto-incremented column where if I change 8 to 9 it will change everything else accordingly.
Is this possible?
The answer to your question is "No" IDENTITY is the only auto incrementing capability (and these columns are not updatable)
But if this is a display_order field can't you just make it float to allow you to insert items between other items rather than having to shift all other items down to create a gap?
However, when I insert a new record with my software I don't know how to get the highest number in that column and add 1,
Insert MyTable( display_order, .... )
Select (
Select Max(display_order) + 1
From MyTable As T1
), ...
From MyTable
However, I wouldn't recommend this. If display_order is user settable, then I would simply assume relative values. Thus, it wouldn't matter if a user added two values with a display_order = 0. If you really want to go the extra mile and provide the ability to resequence the display_order, you could do it like so:
Update MyTable
Set display_order = Z.NewSeq
From (
Select PKCol
, Row_Number() Over ( Order By display_order ) As NewSeq
From MyTable
) As Z
Join MyTable As T
On T.PKCol = Z.PKCol
Because you only get one IDENTITY column per table, I would probably use a trigger or other mechanism (if there's a centralized insertion stored proc) to default it to one more than the highest number in the table if not provided. This avoids having to SET IDENTITY_INSERT or anything like that.