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.
Related
I have a simple table:
CREATE TABLE [dbo].[Word] (
[WordId] INT IDENTITY (1, 1) NOT NULL,
[NameId] INT NOT NULL
PRIMARY KEY CLUSTERED ([WordId] ASC)
);
I have a unique index on NameId
I am trying to update this table and change one column to a random number:
UPDATE Word SET NameId = ROUND(RAND()*2147483647,0)
I realize there is a very very small chance this will not work but it's actually failing every time even though the table has only a very small number of rows the update always fails and says there's a duplicate.
Can anyone tell me what's happening here and also suggest a way to update this table so that there's no duplicate values of NameId created most of the time.
You are updating every NameId with same value, use WHERE statement to update only one row
EDIT: This should do the trick you are looking for, NewId() generates new id for each row
UPDATE Word SET NameId = abs(checksum(NewId()) % 2147483647)
How many rows do you have? It could be a case of the birthday paradox.
Have you tried doing this:
SELECT ROUND(RAND()*2147483647,0) FROM Word
Do the numbers really need to be pseudo-random? You could use row_number() to make them increment.
I have a table which had an identity column.
for many reasons we had to remove the identity from that column.
I have a system that inserts a value to that table by the old way, passes null for the identity column.
is there a simple way to define identity column to receive a value in case it is passed to it, and if a value of null is passed, to make that table to set a unique value to that field that is not found in that table (act like identity).
What i mean is, if there is value, insert it.
And if the system tries to insert null act like an identity.
Thanks in advance.
A trigger seems like a good choice for this situation, but there are a lot of ways you can handle the situation.
The example below creates an INSTEAD OF insert trigger that gets the columns that were supposed to be inserted, and generates a new value via a function if the ID column is null.
CREATE TRIGGER myTrigger ON myTable
INSTEAD OF INSERT
AS
INSERT INTO myTable (myIDcolumn, anotherColumn)
SELECT COALESCE(myIDColumn, dbo.SomeMethodToCreateID), anotherColumn
FROM inserted
How that SomeTheodToCreateID function is to work is up to you. One thing you could do is change the SELECT to combine max plus row_number:
SELECT (COALESCE(myIDColumn,
(SELECT MAX(myIDColumn) FROM myTable) + ROW_NUMBER() OVER(ORDER BY anotherColumn)
)
...
Try This
DBCC CHECKIDENT ( '[dbo].[Customers]', RESEED, 1 )
I need to update a SQL Server table periodically by inserting new records into it.
The table has an ID column in the form of Company0001 through Company0020 right now.
Let's say I added one record of a new company into the table. I want to fill the ID column with Company0021 for this new record. Can anyone suggest a way to do this?
Thank you so much!
I would strongly suggest to use an identity column. Identity is a mechanism designed and used for this actual purpose and therefore it would be much better in terms of performance.
Nevertheless, if you insist on IDs on the format 'CompanyXXX' I would suggest to use a varchar column. Then you would add a trigger on the insert and update operations. When the trigger runs, it would find out the last 'CompanyXXX' and form the new one. If you need help regarding triggers, you could check this tutorial.
Hope I helped!
My suggestion would be to have an autoincrement field, and then concatenate the company name with the ID.
If you don't want to do it with an ID field, do you want it to happen automatically, or are you going to manage it manually? If automatically, you'll need to write a trigger to intercept the INSERT and change the value there. Shouldn't be too hard to do.
I'd seriously recommend NOT doing this and going down the autoincrement field path. It's better.
Add another column to the table to hold an integer value (in this example SNo) and then write query as
declare #SNo int
select #SNo=max(SNo)+1 from Table_Name
insert into Table_Namevalues (#SNo,'company'+right('0000'+cast(#SNo as varchar(10)),4))
And then see the result
Hope this helps
In case a solution is required as, having only one column with values in desired format you can create a function as:
create table table1(id varchar(100));
Go
create function dbo.fn_GetCompanyIdentity ()
returns varchar(100)
as
begin
declare #CompanyIdentify varchar(100);
select #CompanyIdentify =
(select 'Company' +
right ('00000' + cast (
(
(
case when Not exists (select ROW_NUMBER() over( order by (select 1)) from Table1 ) then 1
else (select top 1 ROW_NUMBER() over( order by (select 1)) as currentRownumber from Table1 order by currentRownumber desc) + 1
end
)
)
as varchar(4))
,4));
return #CompanyIdentify;
end;
go
and then use the function in insert statement as :
insert into Table1 (id)
select dbo.fn_GetCompanyIdentity();
Go
Hope this helps!!
Why dont you just create an auto-increment column and then concatenate "Company" to this column in another column. And for presentation just select "Company+autoincrement" column.
Sybase db tables do not have a concept of self updating row numbers. However , for one of the modules , I require the presence of rownumber corresponding to each row in the database such that max(Column) would always tell me the number of rows in the table.
I thought I'll introduce an int column and keep updating this column to keep track of the row number. However I'm having problems in updating this column in case of deletes. What sql should I use in delete trigger to update this column?
You can easily assign a unique number to each row by using an identity column. The identity can be a numeric or an integer (in ASE12+).
This will almost do what you require. There are certain circumstances in which you will get a gap in the identity sequence. (These are called "identity gaps", the best discussion on them is here). Also deletes will cause gaps in the sequence as you've identified.
Why do you need to use max(col) to get the number of rows in the table, when you could just use count(*)? If you're trying to get the last row from the table, then you can do
select * from table where column = (select max(column) from table).
Regarding the delete trigger to update a manually managed column, I think this would be a potential source of deadlocks, and many performance issues. Imagine you have 1 million rows in your table, and you delete row 1, that's 999999 rows you now have to update to subtract 1 from the id.
Delete trigger
CREATE TRIGGER tigger ON myTable FOR DELETE
AS
update myTable
set id = id - (select count(*) from deleted d where d.id < t.id)
from myTable t
To avoid locking problems
You could add an extra table (which joins to your primary table) like this:
CREATE TABLE rowCounter
(id int, -- foreign key to main table
rownum int)
... and use the rownum field from this table.
If you put the delete trigger on this table then you would hugely reduce the potential for locking problems.
Approximate solution?
Does the table need to keep its rownumbers up to date all the time?
If not, you could have a job which runs every minute or so, which checks for gaps in the rownum, and does an update.
Question: do the rownumbers have to reflect the order in which rows were inserted?
If not, you could do far fewer updates, but only updating the most recent rows, "moving" them into gaps.
Leave a comment if you would like me to post any SQL for these ideas.
I'm not sure why you would want to do this. You could experiment with using temporary tables and "select into" with an Identity column like below.
create table test
(
col1 int,
col2 varchar(3)
)
insert into test values (100, "abc")
insert into test values (111, "def")
insert into test values (222, "ghi")
insert into test values (300, "jkl")
insert into test values (400, "mno")
select rank = identity(10), col1 into #t1 from Test
select * from #t1
delete from test where col2="ghi"
select rank = identity(10), col1 into #t2 from Test
select * from #t2
drop table test
drop table #t1
drop table #t2
This would give you a dynamic id (of sorts)
I have a temp table with the exact structure of a concrete table T. It was created like this:
select top 0 * into #tmp from T
After processing and filling in content into #tmp, I want to copy the content back to T like this:
insert into T select * from #tmp
This is okay as long as T doesn't have identity column, but in my case it does. Is there any way I can ignore the auto-increment identity column from #tmp when I copy to T? My motivation is to avoid having to spell out every column name in the Insert Into list.
EDIT: toggling identity_insert wouldn't work because the pkeys in #tmp may collide with those in T if rows were inserted into T outside of my script, that's if #tmp has auto-incremented the pkey to sync with T's in the first place.
SET IDENTITY_INSERT ON
INSERT command
SET IDENTITY_INSERT OFF
As identity will be generated during insert anyway, could you simply remove this column from #tmp before inserting the data back to T?
alter table #tmp drop column id
UPD: Here's an example I've tested in SQL Server 2008:
create table T(ID int identity(1,1) not null, Value nvarchar(50))
insert into T (Value) values (N'Hello T!')
select top 0 * into #tmp from T
alter table #tmp drop column ID
insert into #tmp (Value) values (N'Hello #tmp')
insert into T select * from #tmp
drop table #tmp
select * from T
drop table T
See answers here and here:
select * into without_id from with_id
union all
select * from with_id where 1 = 0
Reason:
When an existing identity column is selected into a new table, the new column inherits the IDENTITY property, unless one of the following conditions is true:
The SELECT statement contains a join, GROUP BY clause, or aggregate function.
Multiple SELECT statements are joined by using UNION.
The identity column is listed more than one time in the select list.
The identity column is part of an expression.
The identity column is from a remote data source.
If any one of these conditions is true, the column is created NOT NULL instead of inheriting the IDENTITY property. If an identity column is required in the new table but such a column is not available, or you want a seed or increment value that is different than the source identity column, define the column in the select list using the IDENTITY function. See "Creating an identity column using the IDENTITY function" in the Examples section below.
All credit goes to Eric Humphrey and bernd_k
Not with SELECT * - if you selected every column but the identity, it will be fine. The only way I can see is that you could do this by dynamically building the INSERT statement.
Just list the colums you want to re-insert, you should never use select * anyway. If you don't want to type them ,just drag them from the object browser (If you expand the table and drag the word, columns, you will get all of them, just delete the id column)
INSERT INTO #Table
SELECT MAX(Id) + ROW_NUMBER() OVER(ORDER BY Id)
set identity_insert on
Use this.
Might an "update where T.ID = #tmp.ID" work?
it gives me a chance to preview the data before I do the insert
I have joins between temp tables as part of my calculation; temp tables allows me to focus on the exact set data that I am working with. I think that was it. Any suggestions/comments?
For part 1, as mentioned by Kolten in one of the comments, encapsulating your statements in a transaction and adding a parameter to toggle between display and commit will meet your needs. For Part 2, I would needs to see what "calculations" you are attempting. Limiting your data to a temp table may be over complicating the situation.