This question already has answers here:
Migration Access to SQL server 2012
(4 answers)
Closed 8 years ago.
I'm moving a database from MS Access to MS SQL Server 2012. My question involves a data issue we need to resolve for the SQL Server database. We have a main MS Access table that generates an integer key then used in several other tables. In Access, the column autoincrements when a new record is created. The issue we're having is that there are gaps in the Access tables columny where records were (unwisely) deleted. It seems that the solution for the SQL Server version of he table is to migrate the table with that column set as PRIMARY and UNIQUE, without using the IDENTITY value. That means we would no longer get an autoincremented number. We'd have to write some code to create that numbering using a SELECT with MAX(). Is there a better way to resolve this issue?
You have TableA that currently maintains the Primary Key that is used is related tables. You want TableB to now control the creation of this Primary Key. I don't see why you can't continue using an auto-incrementing primary key on TableB to manage the creation of the Primary Key. It doesn't matter that previous values have gaps. SQL Server has a way around that.
You can't convert an exiting column in a table to IDENTITY, but you can create a table in SQL Server with an IDENTITY column, turn the IDENTITY function off, populate it with your own values (gaps and all), and then turn the IDENTITY function back on.
From the documentation on IDENTITY_INSERT:
-- Create products table.
CREATE TABLE products (id int IDENTITY PRIMARY KEY, product varchar(40))
GO
-- Inserting values into products table.
INSERT INTO products (product) VALUES ('screwdriver')
INSERT INTO products (product) VALUES ('hammer')
INSERT INTO products (product) VALUES ('saw')
INSERT INTO products (product) VALUES ('shovel')
GO
-- Create a gap in the identity values.
DELETE products
WHERE product = 'saw'
GO
SELECT *
FROM products
GO
-- Attempt to insert an explicit ID value of 3;
-- should return a warning.
INSERT INTO products (id, product) VALUES(3, 'garden shovel')
GO
-- SET IDENTITY_INSERT to ON.
SET IDENTITY_INSERT products ON
GO
-- Attempt to insert an explicit ID value of 3
INSERT INTO products (id, product) VALUES(3, 'garden shovel').
GO
-- SET IDENTITY_INSERT to OFF.
SET IDENTITY_INSERT products OFF
GO
SELECT *
FROM products
Using this technique, you can convert the Access version of TableB to temp_TableB in SQL Server, where there is no identity column. Then create a real TableB in SQL Server with an IDENTITY column.
Then you could
SET IDENTITY_INSERT TableB ON
INSERT INTO TableB ( {columnlist} )
SELECT * from temp_TableB
SET IDENTITY_INSERT TableB OFF
Now you have TableB populated correctly and ready to create the next auto-incremented IDENTITY value.
Related
I am migrating a large Access application to SQL Server.
One technique that I use in Access is to use a selection table in the frontend joined to a shared backend table to allow the user to select individual records. Once the user has specified the selection, I then use the selection as a criteria to update, export or report on the selected records.
The selection table simply consists of a foreign key field and a boolean field used to display a checkbox for the record selection.
Here is an example showing the equivalent of what I do in Access:
CREATE TABLE tblJob (
JobNumber int NOT NULL,
JobName nchar(255) NULL
)
ALTER TABLE tblJob ADD CONSTRAINT PrimaryKey PRIMARY KEY CLUSTERED
(
JobNumber ASC
)
GO
INSERT INTO tblJob (JobNumber, JobName) VALUES (1, 'Job 1')
INSERT INTO tblJob (JobNumber, JobName) VALUES (2, 'Job 2')
INSERT INTO tblJob (JobNumber, JobName) VALUES (3, 'Job 3')
GO
CREATE TABLE tblSelect (
SelectID int NOT NULL,
Selected int NOT NULL
)
--CREATE UNIQUE NONCLUSTERED INDEX PrimaryKey ON tblSelect (
-- SelectID ASC
--)
ALTER TABLE tblSelect ADD DEFAULT (0) FOR Selected
GO
-- Create a view joining the selection table tblSelect to the data table tblJob
CREATE OR ALTER VIEW vwJobSelected
AS
SELECT
JobNumber,
JobName,
Selected
FROM tblJob
LEFT OUTER JOIN tblSelect ON tblJob.JobNumber = tblSelect.SelectID
GO
-- The application initialises tblSelect with the Job keys
DELETE FROM tblSelect
GO
INSERT INTO tblSelect(SelectID, Selected)
SELECT JobNumber, 0 FROM tblJob
GO
-- The user selects the second record via an editing form in the application
UPDATE vwJobSelected
SET Selected=1
WHERE JobNumber = 2
GO
-- Show the selected record(s)
SELECT *
FROM vwJobSelected
WHERE Selected=1
GO
This works well in Access but will not work in SQL Server for the following reasons:
The selection tblSelect is in the frontend database and therefore is unique to the user/workstation/running instance of the application. However with the migrated database this would create a “heterongenous join” which would join the tables on the client instead of the server and therefore drag the whole data table tblJob across the network.
Access allows the query with the left outer join to be modified seamlessly. However SQL Server will not let you delete records since there are multiple base tables. This would require an INSTEAD OF trigger on the view.
So my question is: What is the recommend method for performing this user selection process in SQL Server?
I have considered:
a) Adding columns for UserName (= SUSER_NAME()) and Workstation (=HOST_NAME()) to tblSelect so that there are user/workstation specific selections available. However I think Access will require a unique index on SelectedID to keep the query updatable and this presents problems.
b) Temporary tables. However I get the impression that these only persist for the duration of a connection to the server and the Access application will surely disconnect and reconnect to the server within the duration of running a session.
c) Asking the good folk at Stack Overflow for advice! :-)
Kind regards
Neil Sargent
I support a data replication product. I have a client who is very frustrated that SQL Server can't have a table with an Identity column that BOTH increments automatically when a row is added without providing a value for that column, and at the same time will accept/use a value when it is provided - and I might add, with both of those things happening continuously at a high rate and across hundreds of tables. They point to other databases that apparently can do this.
Everything I see online and my own experimentation seems to indicate that this simply can't be done in SQL Server, but I wanted to put it out there in case I'm just wrong and missing something. My only advice to them so far has been to switch to a Sequence (instead of Identity) and use it as a default value for the column. I've tested that and it works perfectly like they would want, but they are groaning at the idea of doing that for hundreds of tables. Thanks.
The point of an IDENTITY is that SQL Server is in control of it; you let SQL Server manage the value completely. What you really want is a SEQUENCE as a DEFAULT value.
CREATE TABLE dbo.SomeTable (ID int NOT NULL,
SomeColumn varchar(10));
GO
CREATE SEQUENCE dbo.SomeTableID START WITH 1 INCREMENT BY 1;
GO
ALTER TABLE dbo.SomeTable ADD CONSTRAINT PK_SomeTable PRIMARY KEY CLUSTERED (ID);
ALTER TABLE dbo.SomeTable ADD CONSTRAINT DF_SomeTableID DEFAULT NEXT VALUE FOR dbo.SomeTableID FOR ID;
GO
INSERT INTO dbo.SomeTable (SomeColumn)
VALUES ('abc'),('def');
GO
INSERT INTO dbo.SomeTable(ID,SomeColumn)
VALUES(3,'xyz');
GO
--Errors due to 3 already in use, but intended.
INSERT INTO dbo.SomeTable (SomeColumn)
VALUES ('abc');
GO
INSERT INTO dbo.SomeTable (SomeColumn)
VALUES ('def'); --4
GO
--Cleanup
DROP TABLE dbo.SomeTable;
DROP SEQUENCE dbo.SomeTableID;
db<>fiddle
In SQL Server, I have created a Table with an ID column that I have made an IDENTITY COLUMN,
EmployeeID int NOT NULL IDENTITY(100,10) PRIMARY KEY
It is my understanding, when I use the IDENTITY feature, it auto increments the EmployeeID. What I don't know/not sure is:
Is that IDENTITY number created, unique?
Does SQL search the entire column in the table to confirm the number created does not already exist?
Can I override that auto increment number manually?
If I did manually override that number, would the number I enter be checked to make sure it is not a duplicate/existing ID number?
Thanks for any help provided.
Is that IDENTITY number created, unique?
Yes, Identity property is unique
Does SQL search the entire column in the table to confirm the number created does not already exist? \
It need not, what this property does is, just incrementing the old value
Can I override that auto increment number manually?
Yes, you can. You have to use SET IDENTITY_INSERT TABLENAME ON
If I did manually override that number, would the number I enter be checked to make sure it is not a duplicate/existing ID number?
No, that won't be taken care by SQL Server, you will have to ensure you have constraints to take care of this
Below is a simple demo to prove that
create table #temp
(
id int identity(1,1)
)
insert into #temp
default values
go 3
select * from #temp--now id column has 3
set identity_insert #temp on
insert into #temp (id)
values(4)
set identity_insert #temp off
select * from #temp--now id column has 4
insert into #temp
default values
go
select * from #temp--now id column has 5,next value from the last highest
Updating info from comments:
Identity column will allow gaps once you reseed them,also you can't update them
I need to 'migrate' a table in Oracle, this table has a primary key column with a sequence and a trigger to autoincrement this column mentioned, the process is detailed here.
The question is, I want to migrate this table to SQL Server put I want to take advantage of the identity feature. How can I tweak the table in SQL Server? Taking in count the fact I need to migrate the data and I don't want problems with the autoincrement column; will I lost the previous id assignation in Oracle?
No, you create the table with an identity column, like
MyID int identity([your max ID],1)
then when you insert the oracle data, prior to the insert run this command
SET IDENTITY_INSERT MYTABLE ON
/*insert your records*/
SET IDENTITY_INSERT MYTABLE OFF
-- DUPLICATE OF Best way to get identity of inserted row? --
Well, I got an hard time finding a good title for this one.
I have two tables, with microsoft SQL server. Here's the structure:
TableA ( Id identity, Name varchar(20))
TableB ( Id identity, Name varchar(20))
Mapping ( IdTableA int, IdTableB int)
On TableA, I have an After Insert trigger. I want to "replicate" the insert into TableB, gets the new Ids and insert the mapping between the TableA's id and the TableB's id into the table Mapping.
I have no problem with inserting the data into TableB... but I have an hard time finding how to create a "map" between the two Ids...
Any help would be very appreciated.