Running an alter table alter column statement more than once in SQL Server - sql-server

Are there any negative implications to running an alter table alter column statement more than once in SQL Server?
Say I alter a column's datatype and nullability like this:
--create table
create table Table1
(
Column1 varchar(50) not null
)
go
--insert some records
insert into Table1 values('a')
insert into Table1 values('b')
go
--alter once
alter table Table1
alter column Column1 nvarchar(250) not null
go
--alter twice
alter table Table1
alter column Column1 nvarchar(250) not null
go
The above set of sql all works and I have tested these. I could also test for the properties in the alter statements. The question is that is there any advantage to say checking if the column is not already nullable before altering.
After the first alter, does SQL Server figure out that the table has already been altered and hence the 2nd alter essentially does nothing?
Are there any differences across different versions of SQL Server about how this is handled?
Thanks,
Ilias

This is a metadata only operation.
It doesn't have to read or write any of the data pages belonging to Table1. It isn't quite a no-op though.
It will still start up a transaction, acquire a schema modification lock on the table and update the modified column in the row for this table in sys.sysschobjs (exposed to us through the modified_date column in sys.objects).
Moreover because the table has been modified any execution plans referencing the table will need to be recompiled on next usage.

Related

Change the max value of nvarchar in SQL database without deleting and rebuilding the table

Currently I have a SQL database with a column value of nvarchar(255) I need to change this to be nvarchar(600) when I edit it in the SQL visual studio on the server a warning pops up and states that the table must be deleted and rebuilt for my changes to be made. I DO NOT want to have to do this on the advice on the developer who built the program in the first place. (He is unable to make the change for me at this time).
I have seen a lot of answers that advise to Uncheck "Prevent saving changes that require ..." in the settings but again this is something I am reluctant to do on the advise of many others on this site and elsewhere.
Does anyone have any suggestions on how to change this max value without having to delete and rebuild the table?
Would a simple ALTER statement work? The field does not allow NULL values would something like this work?
ALTER TABLE dbo.myTable
ALTER COLUMN myColumn VARCHAR(600)
SET XACT_ABORT ON
BEGIN TRAN
ALTER TABLE dbo.myTable
DROP CONSTRAINT DF_myTable_myColumn
ALTER TABLE dbo.myTable
ALTER COLUMN myColumn VARCHAR(600) NOT NULL
ALTER TABLE dbo.myTable
ADD CONSTRAINT DF_myTable_myColumn DEFAULT('foo') FOR myColumn
COMMIT TRAN

How to Alter Column from nvarchar(max) to nvarchar(50)

I have an existing table in SQL SERVER 2008 with one of its column as NVARCHAR(MAX) and it only has values of less than 10 characters in it.
This table is in production and has data in it.
I have got a requirement wherein I have to Alter this column from NVARCHAR(MAX) to NVARCHAR(50). The SQL Server gives some Truncation error while doing this operation, even though the data in that column is less than 10 characters.
This is my script:
ALTER TABLE [dbo].[Table] ALTER COLUMN [Column1] NVARCHAR ( 50 ) NOT NULL
First Check Your table data with this query:
SELECT DATALENGTH(Column_Name) AS FIELDSIZE, Column_Name
FROM Table_Name
If everything is fine, you may have checked the Prevent Saving Changes option. Follow these steps to check:
Tools > Designers Uncheck Prevent saving changes that require table re-creation
If you are sure that you wouldn't lose data, then:
Update myTable set myNVMaxCol = left(coalesce(myNVMaxCol,''),50);
Alter table myTable alter column myNVMaxCol nvarchar(50) not null;

Column not found

I tried below in sql server management, in a single query.
alter table add column amount2
update table set amount2=amount
I am getting column amount2 not found.
Can anyone tell me why this error?
That is not valid syntax (misses table name and column datatype) but in management studio use the batch separator GO between adding a column to an existing table and statements referencing the new column anyway.
Or alternatively you can use EXEC to execute it in a child batch.
SQL Server tries to compile all statements in the batch before execution and this will fail when it encounters the statement using this column.
There's a couple things wrong here.
The correct syntax for adding a column is MSDN - ALTER TABLE
ALTER TABLE [TableName] ADD [ColumnNAME] [DataType]
'Table' is a Reserved Keyword in SQL Server, although it is possible to have a table named 'Table'. You need to include brackets when referencing it.
SELECT * FROM [Table]
All together, you need
ALTER TABLE [Table] ADD [Amount2] INT
GO -- See Martin's answer for reason why 'GO' is needed here
UPDATE [Table] SET [Amount2] = [Amount]
You can get around this problem like this:
-- Alter the table and add new column "NewColumn"
ALTER TABLE [MyTable] ADD [NewColumn] CHAR(1) NULL;
-- Set the value of NewColumn
EXEC ('UPDATE [MyTable] SET [NewColumn] = ''A'' ');

SQL Server : alter table type

What happens when you execute the same alter column several times, e.g:
ALTER table1 ALTER column column1 varchar(40)
ALTER table1 ALTER column column1 varchar(40)
...
Does SQL Server compare altering types in first place or does it use the same mechanism for every alter?
You can check the transaction log, or use table change tracking, or use CDC to track, then you will find out what id the difference between first time and second time. You will see no difference.

SQL Server, How to set auto increment after creating a table without data loss?

I have a table table1 in SQL server 2008 and it has records in it.
I want the primary key table1_Sno column to be an auto-incrementing column. Can this be done without any data transfer or cloning of table?
I know that I can use ALTER TABLE to add an auto-increment column, but can I simply add the AUTO_INCREMENT option to an existing column that is the primary key?
Changing the IDENTITY property is really a metadata only change. But to update the metadata directly requires starting the instance in single user mode and messing around with some columns in sys.syscolpars and is undocumented/unsupported and not something I would recommend or will give any additional details about.
For people coming across this answer on SQL Server 2012+ by far the easiest way of achieving this result of an auto incrementing column would be to create a SEQUENCE object and set the next value for seq as the column default.
Alternatively, or for previous versions (from 2005 onwards), the workaround posted on this connect item shows a completely supported way of doing this without any need for size of data operations using ALTER TABLE...SWITCH. Also blogged about on MSDN here. Though the code to achieve this is not very simple and there are restrictions - such as the table being changed can't be the target of a foreign key constraint.
Example code.
Set up test table with no identity column.
CREATE TABLE dbo.tblFoo
(
bar INT PRIMARY KEY,
filler CHAR(8000),
filler2 CHAR(49)
)
INSERT INTO dbo.tblFoo (bar)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM master..spt_values v1, master..spt_values v2
Alter it to have an identity column (more or less instant).
BEGIN TRY;
BEGIN TRANSACTION;
/*Using DBCC CHECKIDENT('dbo.tblFoo') is slow so use dynamic SQL to
set the correct seed in the table definition instead*/
DECLARE #TableScript nvarchar(max)
SELECT #TableScript =
'
CREATE TABLE dbo.Destination(
bar INT IDENTITY(' +
CAST(ISNULL(MAX(bar),0)+1 AS VARCHAR) + ',1) PRIMARY KEY,
filler CHAR(8000),
filler2 CHAR(49)
)
ALTER TABLE dbo.tblFoo SWITCH TO dbo.Destination;
'
FROM dbo.tblFoo
WITH (TABLOCKX,HOLDLOCK)
EXEC(#TableScript)
DROP TABLE dbo.tblFoo;
EXECUTE sp_rename N'dbo.Destination', N'tblFoo', 'OBJECT';
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;
PRINT ERROR_MESSAGE();
END CATCH;
Test the result.
INSERT INTO dbo.tblFoo (filler,filler2)
OUTPUT inserted.*
VALUES ('foo','bar')
Gives
bar filler filler2
----------- --------- ---------
10001 foo bar
Clean up
DROP TABLE dbo.tblFoo
SQL Server: How to set auto-increment on a table with rows in it:
This strategy physically copies the rows around twice which can take a much longer time if the table you are copying is very large.
You could save out your data, drop and rebuild the table with the auto-increment and primary key, then load the data back in.
I'll walk you through with an example:
Step 1, create table foobar (without primary key or auto-increment):
CREATE TABLE foobar(
id int NOT NULL,
name nchar(100) NOT NULL,
)
Step 2, insert some rows
insert into foobar values(1, 'one');
insert into foobar values(2, 'two');
insert into foobar values(3, 'three');
Step 3, copy out foobar data into a temp table:
select * into temp_foobar from foobar
Step 4, drop table foobar:
drop table foobar;
Step 5, recreate your table with the primary key and auto-increment properties:
CREATE TABLE foobar(
id int primary key IDENTITY(1, 1) NOT NULL,
name nchar(100) NOT NULL,
)
Step 6, insert your data from temp table back into foobar
SET IDENTITY_INSERT temp_foobar ON
INSERT into foobar (id, name) select id, name from temp_foobar;
Step 7, drop your temp table, and check to see if it worked:
drop table temp_foobar;
select * from foobar;
You should get this, and when you inspect the foobar table, the id column is auto-increment of 1 and id is a primary key:
1 one
2 two
3 three
If you want to do this via the designer you can do it by following the instructions here "Save changes is not permitted" when changing an existing column to be nullable
Yes, you can. Go to Tools > Designers > Table and Designers and uncheck "Prevent Saving Changes That Prevent Table Recreation".
No, you can not add an auto increment option to an existing column with data, I think the option which you mentioned is the best.
Have a look here.
If you don't want to add a new column, and you can guarantee that your current int column is unique, you could select all of the data out into a temporary table, drop the table and recreate with the IDENTITY column specified. Then using SET IDENTITY INSERT ON you can insert all of your data in the temporary table into the new table.
Below script can be a good solution.Worked in large data as well.
ALTER DATABASE WMlive SET RECOVERY SIMPLE WITH NO_WAIT
ALTER TABLE WMBOMTABLE DROP CONSTRAINT PK_WMBomTable
ALTER TABLE WMBOMTABLE drop column BOMID
ALTER TABLE WMBOMTABLE ADD BomID int IDENTITY(1, 1) NOT NULL;
ALTER TABLE WMBOMTABLE ADD CONSTRAINT PK_WMBomTable PRIMARY KEY CLUSTERED (BomID);
ALTER DATABASE WMlive SET RECOVERY FULL WITH NO_WAIT

Resources