Why is data table in VB 2010 and SQL Server starting with a negative primary key? - sql

I defined a database using SQL Server 2008 R2 Express, and connected to it using Visual Basic 2010 Express. For some reason though, when I use the database in the program, it wants to start off using a negative primary key.
Is there any way to make the primary key only a positive number?

In addition to #RNarry Young response. You can check the schema if your table
Suppose you have the following table
create table #t
(
ID int Identity(-1, 1),
s varchar(100)
)
Now you make two inserts
Insert into #t(s) values('ed')
Insert into #t(s) values('ed')
Check the output
select * from #t
It shows like below. If you see the screen shot. The first row shows -1 in the primary key value. Due to the reason that the Identity Seed is -1 mentioned in the schema.
You can get rid of this issue. We should use the schema like below.
create table #t
(
ID int Identity(1, 1),
s varchar(100)
)
Following is the other way to generate
Set Identity_Insert #t On
Insert into #t(ID, s) values(-1, 'ed')
Set Identity_Insert #t OFF
Set Identity_Insert #t On
Insert into #t(ID, s) values(-2, 'ed')
Set Identity_Insert #t OFF

Off hand I can only think of two things that would cause this:
When creating the table you (or some software/code you are using) is setting the Identity seed to a negative number.
Or, you (or some software/code you are using) are using Identity_Insert and just forcing a negative number in.

The identity seed for the table will be visible within SSMS.
But.... it doesn't matter in the slightest that it's producing negative numbers. There's only really two practical concerns about your identiity value:
Unique values
Sufficient space to cover the expected range of values (so, a tinyint key wouldn't be great for tracking the entire world population...)
Once they're sorted, the actual values shouldn't be of any concern at all. They're internal to the database.

Related

Need to create a Run id for each package run in SSIS Package

I have an SSIS Package that runs a query and inserts values into a different table. Each time the package runs, I want to create a unique RunID for the results of that run. Here are the columns from my table. I have tried this using the Execute SQL Task and setting up the User::RunID variable but, I believe I am doing something wrong. Can anyone provide step by step instructions on how to do this?
You need 2 tables for this.
create table runs(
runID int identity primary key,
runDateTime datetime default getdate()
)
create table runReturns(
runReturnsID int identity primary key,
runID int not null,
[the rest of the data set]
)
In ssis, start with an execute SQL.
Add this query...
insert into runs (runDateTime) values(?);
select SCOPE_IDENTITY()
Map the parameter (?) to Now();
Change the result set to single row and map the first column to a parameter called runID.
Now create a data flow.
Insert your query into a sql source.
Add a derived column and map a new column to runID.
Finally, add a destination to your table and map accordingly.
Adding a completely sql answer to compliment as an alternative since there are no transformations at all:
Same 2 tables:
create table runs(
runID int identity primary key,
runDateTime datetime default getdate()
)
create table runReturns(
runReturnsID int identity primary key,
runID int not null,
[the rest of the data set]
)
Create a Job.
Add a step and base it on SQL.
declare #runID int;
insert into runs(runDateTime) values(getdate());
select #runID = scope_idenity();
insert into runReturns(
runID, [rest of your columns])
select #runID
, [rest of your columns]
from [rest of your query]
An approach that might solve the issue, is the system scoped variable ServerExecutionID By default, System scoped variables are hidden in the Variables menu but you can expose them by clicking the Grid options button (rightmost of the 5).
If you reference that variable using the appropriate placeholder (? for OLE/ODBC or a named parameter for ADO) and map to the variable, then every server execution will have a monotonically increasing number associated to it. Runs from Visual Studio or outside of the SSISDB, will always have a value of 0 associated to them but given that this is only encountered during development, this might address the issue.
Sample query based on the newer picture
INSERT INTO dbo.RunMapTable
SELECT ? AS RunID
, D.Name
FROM
(
VALUES ('A')
, ('B')
, ('C')
, ('D')
)D([name];
Parameter Mapping
0 -> System::ServerExecutionID
As an added bonus, you can then tie your custom logging back to the native logging in the SSISDB.

SQL Server - Generate script without primary key

I'm trying to make a generated script of my data (I mean, all the INSERT INTO commands).
Because access permissions, I can't do a SET IDENTITY_INSERT TABLE OFF and ON (I'm using the user application in Staging)
So, there is a way to make this script in SQL Server Manager and avoid the field with the primary key?
I set to false all properties (primary, unique, etc), but the script is still sending this field (For e.g., RecID 1, 2, 3, etc).
I'm using SQL Server 2012.
My configuration for the script:
Results I get:
SET IDENTITY_INSERT -TABLE- ON
INSERT INTO TABLE (ID,Field1) VALUES (1,'value')
Any solution (except for removing it with Notepad++) is appreciated.
A bit of a work around, but sometimes useful quick and dirty way of doing these things:
SELECT 'INSERT INTO TABLE (Field1) VALUES (''' + Field1 + ''')' FROM TABLE
The result set will be a row for each insert statement for every row in the table TABLE. The INSERT statement is generated from concatenating the INSERT statement text with the values in Field1.
There is another way to do this which is a bit more automatic and a lot less faffy when you have a lot of columns of different data types; given a table T:
(
ID int identity,
C1 nvarchar(255),
C2 datetime
...
)
...select everything except the identity column into a new table:
select C1, C2, ... into InterimTable from T
Then:
Run the Generate Scripts wizard on InterimTable.
Use whatever tool you have to search the SQL for InterimTable and replace with T
Run

SQL IDENTITY COLUMN

I have an sql table which is basically a statement.
Now lets say the records I have in my table have a date and an identity column which is autonumbered and defines the order which the transactions are displayed in the front end to the client.
The issue is during an insert some of the data have gone missing and some transactions between two dates are missing.
I need to insert the data into the table, but I need to insert them between the dates and not at the end of the table. If I do a a normal insert, the data will appear at the end of the table and not at the date I specify, because the identity column is autonumbered, and cannot be updated.
Using SET IDENTITY_INSERT (table) ON, you force SQL Server to let you insert any arbitrary value into an IDENTITY column - but there's no way to update an IDENTITY column.
What's the big problem with a few gaps anyway?? Yes, it might be a bit of a "cosmetic" problem - but how much hassle and effort do you really want to spend on cosmetic problems?? The order of the entries is still a given - even with gaps.
So again: what's the big deal?? IDENTITY columns are guaranteed to be ever increasing - that's all they guarantee. And for 99% of the cases, that's more than good enough....
Why not just display the records in the user interface sorted by the date, rather than by the primary key?
OK, if you really want to do this (personally, I think changing the sort date in the UI is going to be easier than updating the primary key values in the database, but anyway...). This should work, assuming you're not using the primary key values in any foreign key constraints (if you are, then you'll need to make sure those constraints have ON UPDATE CASCADE set)
SET IDENTITY_INSERT tablename ON
UPDATE tablename SET
primary_key = primay_key + 1
WHERE
primary_key >= <the primary key where you want to insert the new date>
INSERT INTO tablename
(primary_key, date, ...)
VALUES
(<the primary key to insert>, <the date to insert>, ...)
SET IDENTITY_INSERT tablename OFF
However, I strongly, strongly suggest you backup your database before attempting this.
Just out of curiosity, is it one ID per date? Your answers imply this a little, so if so, replace the Identity column with a computed column that is defined as the date difference in days from an arbitrary starting point?
DECLARE #EXAMPLE TABLE
(
[Date] DATE,
ID AS DATEDIFF(Day, '1 Jan 2010', [Date])
)
INSERT INTO #EXAMPLE([Date])
VALUES (GETDATE()), (GETDATE()+1), (GETDATE()+2)
SELECT * FROM #EXAMPLE

Asking a Microsoft SQL Server database for the next auto-generated identifier on a table

I have a table in a SQL Server database that has an auto-generated integer primary key. Without inserting a record into the table, I need to query the database and get what the next auto-generated ID number will be.
I think it's SQL Server version 2005, if that makes a difference.
Is there a way to do this?
Yes, but it's unreliable because another session might use the expected number.
If you still want to do this, use IDENT_CURRENT
Edit, as the comments have pointed out (improving my answer):
you need to add one IDENT_INCR('MyTable') to this to get the potential next number
another process may rollback and this number may not be the one used anyway
No, there is not. The ID will only ever be defined and handed out when the actual INSERT happens.
You can check the last given ID by using
DBCC CHECKIDENT('YourTableName')
but that's just the last one used - no guarantee that the next one is really going to be this value + 1 - it could be - but no guarantees
The only way to get a number that is guranteed not to be used by another process (i.e., a race condition) is to do the insert - is there any reason you can't do a NULL insert (i.e., just insert into the table with NULLs or default values for all other columns) and then subsequently UPDATE it?
i.e.,
CREATE TABLE bob (
seq INTEGER IDENTITY (1,1) NOT NULL,
col1 INTEGER NULL
)
GO
DECLARE #seqid INTEGER
INSERT INTO bob DEFAULT VALUES
SET #seqid = SCOPE_IDENTITY()
-- do stuff with #seqid
UPDATE bob SET col1 = 42 WHERE seq = #seqid
GO
You shouldn't use the technique in code, but if you need to do it for investigative purposes:
select ident_current(‘foo’) + ident_incr(‘foo’)
That gives you the last value generated + the incrementation for the identity, so should represent the next choice SQL would make without inserting a row to find out. This is a correct value even if a rollback has pushed the value forwards - but again, this is investigative SQL not stuff I would put in code.
The two values can also be found in the sys.identity_values DMV, the fields are increment_value and last_value.
Another way, depending on what your doing, is inserting whatever data goes into the table, and then using ##identity to retrieve the id of the record inserted.
example:
declare #table table (id int identity(1,1), name nvarchar(10))
insert into #table values ('a')
insert into #table values ('b')
insert into #table values ('c')
insert into #table values ('d')
select ##identity
insert into #table values ('e')
insert into #table values ('f')
select ##identity
This is pretty much a bad idea straight off the bat, but if you don't anticipate high volume and/or concurrency issues, you could just do something like this
select #nextnum = max(Id) + 1 from MyTable
I don't think thats possible out of the box in MS SQL (any version). You can do this with column type uniqueidentifier and using function NEWID().
For int column, you would have to implement your own sequential generator.

Share auto-incremented primary key between two tables

Hi I want to have two tables each have an INT "id" column which will auto-increment but I don't want either "id" columns to ever share the same number. What is this called and what's the best way to do it? Sequence? Iterator? Index? Incrementor?
Motivation: we're migrating from one schema to a another and have a web-page that reads both tables and shows the (int) ID, but I can't have the same ID used for both tables.
I'm using SQL Server 9.0.3068.
Thanks!
Just configure the identity increment to be >1 e.g. table one uses IDENTITY (1, 10) [1,11,21...] and table two uses IDENTITY (2, 10) [2,12,22...]. This will also give you some room for expansion if needed later.
I think using a GUID would be the most straightforward way, if I understand you correctly.
SELECT NEWID()
Use a column with GUID (Globally Unique Identifier) type. It's 16 byte and will be always unique for each row.
Just be aware that you'll get a significant performance hit comparing to normal integer keys.
Use another table with an ID key of type int default it to 1, called KeyID or whatever.
Have a stored procedure retrieve the value, add 1, then update the KeyID, then return this to the stored procedure which is updating your two tables which needs the new unique key.
This will ensure the ID is an int, and that it's unique between the set of tables which are using the stored procedure to generate new ID's.
You can define an IDENTITY column in a third table, use that to generate ID values, but you always roll back any inserts you make into the table (to avoid making it grow). Rolling back the transaction doesn't roll back the fact that the ID was generated.
I'm not a regular user of Microsoft SQL Server, so please forgive any syntax gaffes. But something like the following is what I have in mind:
CREATE TABLE AlwaysRollback (
id IDENTITY(1,1)
);
BEGIN TRANSACTION;
INSERT INTO AllwaysRollBack () VALUES ();
ROLLBACK TRANSACTION;
INSERT INTO RealTable1 (id, ...) VALUES (SCOPE_IDENTITY(), ...);
BEGIN TRANSACTION;
INSERT INTO AllwaysRollBack () VALUES ();
ROLLBACK TRANSACTION;
INSERT INTO RealTable2 (id, ...) VALUES (SCOPE_IDENTITY(), ...);
I don't know what you would call it.
If you don't want to use a GUID or a separate table, you could also create a function that looked at the max values of the ids from both tables and added one to the that value (or something like that).
You could then call that function in an insert trigger on both tables.
I am personally a fan of the GUID solution, but here is a viable option.
Many solutions to this problem have avoided GUID and used good old integer. This is common also with merge replication situations where many satellite sites merge with a master and key conflicts need to be avoided.
If GUID will not work for you, and you absolutely must have int, bigint, or the like, you can always just use an IDENTITY column and have each table with a different value for SEED. Those datatypes have a very wide range, and it is not too hard to split the range into usable segments, especially if all you want is two splits. As an example, basic int has a range from -2^31 (-2,147,483,648) through 2^31 - 1 (2,147,483,647). This is more than enough for a customer table, for example.
Transact-SQL Reference (SQL Server 2000)
int, bigint, smallint, and tinyint
Example:
--Create table with a seed of 1 billion and an increment of 1
CREATE TABLE myTable
(
primaryKey int IDENTITY (1000000000, 1),
columnOne varchar(10) NOT NULL
)
If you really need to do this with an int and you have an auto incrementing number, the way i have done this before is to change the id field auto increment function to the sequence of the other table. I am not too sure in ms sql or my sql but in pgsql that means that in the sql you would have this field
id integer NOT NULL DEFAULT nextval('table_two_seq'::regclass),
where table_two_sequence is the sequence function for the other table. Then test it out by inserting some data. I am really sorry if this wont work in ms sql i try to steer clear of it tbh. Failing that the GUID is the best way as has been mentioned by others. Or when inserting in the code that you use you could put an algorithm in that but it could get messy.
Alternatively, think about having the data in one table as this would be a way around it. if you need to you could have a view simulating two tables. Just a thought.
Hope i have helped
Starting with SQL Server 2012 you can declare a sequence object
https://msdn.microsoft.com/en-us/library/ff878091.aspx which is exactly what you need.
I should be pretty trivial to emulate a sequence object with a table
containing the next sequence value and a stored procedure atomically
select the value and increment. [You'd liked to use function, but functions
can't have side effects.]
How about this hack? Create a table (MySequence) with two columns: And Identity column (SequenceValue) and a dummy column (DummyValue) and use this stored procedure to get a new sequence value. The only row in the table will be last sequence value retrieved.
CREATE PROCEDURE GetNextValue
AS
BEGIN
DECLARE #value int = null;
-- Insert statements for procedure here
INSERT into MySequence (DummyValue) Values (null);
SET #value = SCOPE_IDENTITY();
DELETE from MySequence where SequenceValue <> #value
SELECT #value as Sequence
return #value
END
To use the sequence you'd have to manage the inserts to the target tables--a trigger would probably work.