SQL multiple tables with synced IDENTITY columns - sql

I am working on "cleaning up" a database and need to synchronize the IDENTITY columns. I am using stored procedures to handle the data and mirror it from one table to the next (after cleaning it and correcting the datatypes). At some point in the future I will want to cut off the old table and use only the new table, my question is how to have the IDENTITY field stay in sync while they are both in use... Once the old table is removed the new one will need to continue auto-incrementing and rebuilding/altering it to change the IDENTITY field is not an option. Is this possible or is there a better way to go about this?
My other thought was to create a lookup table to store the ID columns of both tables and anytime there is an insert in the new table take the old ID and new ID and insert them into the lookup table. This is kind of messy once the old table is out of the way tho.

Been there, done that. Put the old id in the new table as an FK. Drop that column just before you drop the old table.

Set the new table's identity to be a non-identity field.
Modify either your data population procedures to populate the non-identity field on your new table with the old table's identity value.
At cutover, switch your new field to auto-increment and set the seed number accordingly.

Related

Insert & Delete from SQL best practice

I have a database with 2 tables: CurrentTickets & ClosedTickets. When a user creates a ticket via web application, a new row is created. When the user closes a ticket, the row from currenttickets is inserted into ClosedTickets and then deleted from CurrentTickets. If a user reopens a ticket, the same thing happens, only in reverse.
The catch is that one of the columns being copied back to CurrentTickets is the PK column (TicketID)that idendity is set to ON.
I know I can set the IDENTITY_INSERT to ON but as I understand it, this is generally frowned upon. I'm assuming that my database is a bit poorly designed. Is there a way for me to accomplish what I need without using IDENTITY_INSERT? How would I keep the TicketID column autoincremented without making it an identity column? I figure I could add another column RowID and make that the PK but I still want the TicketID column to autoincrement if possible but still not be considered an Idendity column.
This just seems like bad design with 2 tables. Why not just have a single tickets table that stores all tickets. Then add a column called IsClosed, which is false by default. Once a ticket is closed you simply update the value to true and you don't have to do any copying to and from other tables.
All of your code around this part of your application will be much simpler and easier to maintain with a single table for tickets.
Simple answer is DO NOT make an Identity column if you want your influence on the next Id generated in that column.
Also I think you have a really poor schema, Rather than having two tables just add another column in your CurrentTickets table, something like Open BIT and set its value to 1 by default and change the value to 0 when client closes the Ticket.
And you can Turn it On/Off as many time as client changes his mind, with having to go through all the trouble of Insert Identity and managing a whole separate table.
Update
Since now you have mentioned its SQL Server 2014, you have access to something called Sequence Object.
You define the object once and then every time you want a sequential number from it you just select next value from it, it is kind of hybrid of an Identity Column and having a simple INT column.
To achieve this in latest versions of SQL Server use OUTPUT clause (definition on MSDN).
OUTPUT clause used with a table variable:
declare #MyTableVar (...)
DELETE FROM dbo.CurrentTickets
OUTPUT DELETED.* INTO #MyTableVar
WHERE <...>;
INSERT INTO ClosedTicket
Select * from #MyTableVar
Second table should have ID column, but without IDENTITY property. It is enforced by the other table.

Replace identity column from int to bigint

I am using SQL Server 2008, and I have a table that contains about 50 mill rows.
That table contains a primary identity column of type int.
I want to upgrade that column to be bigint.
I need to know how to do that in a quick way that will not make my DB server unavailable,
and will not delete or ruin any of my data
How should I best do it ? what are the consequences of doing that?
Well, it won't be a quick'n'easy way to do this, really....
My approach would be this:
create a new table with identical structure - except for the ID column being BIGINT IDENTITY instead of INT IDENTITY
----[ put your server into exclusive single-user mode here; user cannot use your server from this point on ]----
find and disable all foreign key constraints referencing your table
turn SET IDENTITY_INSERT (your new table) ON
insert the rows from your old table into the new table
turn SET IDENTITY_INSERT (your new table) OFF
delete your old table
rename your new table to the old table name
update all table that have a FK reference to your table to use BIGINT instead of INT (that should be doable with a simple ALTER TABLE ..... ALTER COLUMN FKID BIGINT)
re-create all foreign key relationships again
now you can return your server to normal multi-user usage again
What am I missing?
Why can't you just do this:
ALTER TABLE tableName ALTER COLUMN ID bigint
I guess try it in a test environment first but this always works for me
Probably the best way is to create a new table with a BIGINT IDENTITY column, move the existing data using SET IDENTITY_INSERT ON; and then rename the tables. You will need to do this during a maintenance window, just as you would if you changed the data type in Management Studio (which would similarly create a new table, move the data, and block everyone in the process).
You could use Alter script for your column as #MobileMon said, but couldn't do this before removing constraints. And besides FK constraints, you must also remove PK constraint before changing the column type!
Also there is another creative way, if the ID data is not important (No FK etc):
Take a Backup of table (if it's in a separate FileGroup) or DB
Rename table (Having no more inserts)
Remove PK/Constraints from the column
Drop ID column
Add new ID column, with Identity
Apply PK
Rename table back to original name (back to work :) )
& If the ID data is important:
Step 1,2 like above
Create a new column
Transfer the data from the existing IDENTITY column to the new column
Drop the existing IDENTITY column & PK.
Make new column, with Identity
Apply PK
Rename table back to original name (back to work :) )
Important Note: 1. If the old column ID value in not important & there are big gaps between your values(you have deletes besides inserts), you don't need BigInt. Just make the new ID column as Int again.
2. When table grows & is reaching Overflow value(2 billion) you could look at the actual row number in properties, storage of your table. Maybe your reaching overflow, but your row number is much less than that.
Why would someone want to use a BigInt instead of Int as an IDENTITY?
Consider this scenario:
Your database exists in several environments including 1 instance in a live Production environment and several other instances in (TestA, B, C, etc.), (QA A, B, C, etc.), (Demo A, B, C, etc), (UAT A, B, C, etc.), (Training A, B, C, etc.) on and on and on... You don't even want to know...
This database IDENTITY field is used to pass in an unique number to a 3rd party provider which is a shared environment in the Non Production environments. The vendor charges an arm and a leg in order to set up multiple environments so the company has one for the production DB and one for ALL the others.
So... when testing happens in the non production environments these numbers can never cross each other from whatever non production environment you happen to be testing in. And the testing includes stress testing... sending 100's of thousands of rows at a time.
To top it off... ALL these environments get refreshed with Production so the Identity field gets reset with whatever was in production. So one has to keep track of what spread was used in each environment and then reset the IDENTITY to a new spread that has never been used before. The 3rd party vendor will puke if an already number gets sent again in these environments. And the vendor is unwilling or unable to refresh or reset these numbers on their end.
This is a real world issue and the current field remains to be an int in ALL environments and the management of keeping track of these spreads is updated every quarter or whenever someone does a massive stress testing 100's of thousands of transactions.
So in about 10 years this IDENTITY will have to be updated to a BIGINT or someone will have to convince the 3rd party vendor to refresh on their end.
Oh yeah, management could give a rat's ass about it until everything comes crashing down all of a sudden.
Then the HACK "ALTER TABLE tableName ALTER COLUMN ID bigint" will do just fine.
Space and index processing is CHEAP!

SQLite3 : How to modify fileds'type without data loss

In my project I use a sqlite database, unfortunately my friend have make an error. A field is with no correct type.
So for the moment when the data in the field 'localid' (declare as integer) is more than 2147483647, all entry in this field is set to the max 2147483647.
The alter table/alter column sql request do not works with sqlite because it supports a limited subset of ALTER TABLE : only rename and add a new column.
So how can I make a change without data loss? create a new database correctly, coppy all data into it and delete the old?
But maybe there is a better way ? Someone have an idea?
Proceed like this:
create temporary table that contains fields that form the primary
key and localid (I assume this is nor PK).
fill temporary table
drop old column
add new column
fill new column by selecting from temporary table (+ possible conversion to new type).
Don't forget possible foreign keys if column is used as such and remember possibility to temporally relax constraint if it makes conversion smooth (likely not needed in your case).

If exist update else insert records in SQL Server 2008 table

I have one staging table and want to insert data to Main table, so i want to check while inserting data from staging to Main table, if exists then update the records else insert as new records. Here the issue is both the staging as well as Main table does not have any key column based on which i can compare values.
Is it possible to do without having key columns i.e. primary key on both the tables? if yes, please, suggest me how.
Thanks in advance.
If there is no unique key or set of data within a row to define uniqueness, then no.
The set of data can be a combination of the data in each column, creating a sum of parts which will provide uniqueness; however without exposure to your data you would need to make that decision.
You write the WHERE-clause to include all the fields that make your record unique (ie. the fields that decide whether the record is new or should be updated.)
Take a look at this article (http://blogs.msdn.com/b/miah/archive/2008/02/17/sql-if-exists-update-else-insert.aspx) for hints on how to construct it.
If you are using SQL Server 2008r2, you could also use the MERGE statement - I haven't tried it on tables without keys, so I don't know whether it would work for you.

Add Indentity (auto-increment) to primary key of existing table [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Adding an identity to an existing column
how to set auto increment after creating a table without any data loss?
I have a table Activities with two columns: Activity and ActivityId. ActivityId is the primary key. This table is referenced by a Users Table, which has an ActivityId column (this column is not marked as a foreign key - is this a problem?)
When this table was created, I thought it was going to be pretty static, but now I find I need to be able to add and remove rows from it fairly often, so I want to make the ActivityId column auto increment when rows are added to it. I've read that in sql server, I do this by making the column the Identity column, but that this only works for new tables.
How do I add an identity to an existing table, while keeping the database consistant? For instance, it's ok if the IDs are renumbered, so long as this change propagates through to the user table.
I tried to add the identity in SQL Server Management Studio, but it wouldn't let me save the changes due to needing to drop and recreate the table.
You need to either:
Add a NEW column that has the identity property, and alter your PK to include that field (and I highly recommend you do an ALTER TABLE REBUILD afterwards to clean up all the pointers you will create from page splits)
Create a new table with the desired structure and put all your existing data into it
If you are on Enterprise / Developer edition see my answer here otherwise it is not possible without rebuilding the table.
Enabling this in SSMS is just an option you can set then it will generate the whole script for you that preserves existing identity values (Tools -> Options -> Designers -> Untick "prevent saving changes that require table re-creation")