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

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

Related

Running an alter table alter column statement more than once in 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.

Add a new table column to specific ordinal position in Microsoft SQL Server

Is it possible to add a column to a table at a specific ordinal position in Microsoft SQL Server?
For instance, our tables always have CreatedOn, CreatedBy, LastModifiedOn, LastModifiedBy columns at the "end" of each table definition? I'd like the new column to show up in SSMS above these columns.
If I am scripting all my database changes, is there a way to preserve this order at the end of the table?
FYI, I'm not trying to institute a flame war on if this should even be done. If you want to read about a thread that degenerates quickly into that, here's a good one:
http://www.developersdex.com/sql/message.asp?p=581&r=5014513
You have to create a temp table that mirrors the original table's schema but with the column order that you want, then copy the contents of the original to temp. Delete the original and rename the temp.
This is what SQL Management Studio does behind the scenes.
With a schema sync tool, you can generate these scripts automatically.
go into SQL Server management Studio, and "design" an existing table. Insert a column in the middle, right click in an empty area and select Generate Change Script...
Now look at the script it creates. it will basically create a temp table with the proper column order, insert the data from the original table, drop the original table, and rename the temp table. This is probably what you'll need to do.
You may also need to uncheck this option to allow creation of change scripts
The answer is yes, it is technically possible, but you will have a headache doing so and it will take a long time to execute and set up.
One: Create/Copy/Drop/Rename
This is actually what SQL Server is doing in the graphical interface: here's an example of the script it is generating and executing when you click the 'save' button after adding a new column to the beginning of a table.
/* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_SomeTable
(
MyNewColumn int NOT NULL,
OriginalIntColumn int NULL,
OriginalVarcharColumn varchar(100) NULL
) ON [PRIMARY]
TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_SomeTable SET (LOCK_ESCALATION = TABLE)
GO
SET IDENTITY_INSERT dbo.Tmp_SomeTable ON
GO
IF EXISTS(SELECT * FROM dbo.SomeTable)
EXEC('INSERT INTO dbo.Tmp_SomeTable (OriginalIntColumn, OriginalVarcharColumn FROM dbo.SomeTable WITH (HOLDLOCK TABLOCKX)')
GO
SET IDENTITY_INSERT dbo.Tmp_SomeTable OFF
GO
DROP TABLE dbo.SomeTable
GO
EXECUTE sp_rename N'dbo.Tmp_SomeTable', N'SomeTable', 'OBJECT'
GO
GO
COMMIT
Two: ADD COLUMN / UPDATE / DROP COLUMN / RENAME
This method basically involves creating a copy of any existing columns that you want to add to the 'right' of your new column, transferring the data to the new column, then dropping the originals and renaming the new ones. This will play havoc with any indexes or constraints you have, since you have to repoint them. It's technically possible, but again time-consuming both in terms of development and execution.
CREATE TABLE MyTest (a int, b int, d int, e int)
INSERT INTO MyTest (a,b,d,e) VALUES(1,2,4,5)
SELECT * FROM MyTest -- your current table
ALTER TABLE MyTest ADD c int -- add a new column
ALTER TABLE MyTest ADD d_new int -- create copies of the existing columns you want to move
ALTER TABLE MyTest ADD e_new int
UPDATE MyTest SET d_new = d, e_new = e -- transfer data to the new columns
ALTER TABLE MyTest DROP COLUMN d -- remove the originals
ALTER TABLE MyTest DROP COLUMN e
EXEC SP_RENAME 'MyTest.d_new', 'd'; -- rename the new columns
EXEC SP_RENAME 'MyTest.e_new', 'e';
SELECT * FROM MyTest
DROP TABLE MyTest -- clean up the sample
Three: Live with it
This mightily offends my sense of order ... but sometimes, it just isn't worth reshuffling.
To my knowledge there is no known method to change the order of the column. Behind the scenes SQL Management Studio does what Jose Basilio said. And if you have a big table then it is impractical to change the column orders like this way.
You can use a "view". With SQL views you can use any order you like without getting affected by the table column changes.
I am using SSMS 18. I did in simple way
Opened design of table
positioning the required column by dragging it
And as per the answer from KM (second in thread) - uncheck the option to allow creation of change scripts refer image above.
Save the changes.
Done. Check your table now.
TFS 2013 will do this for you automatically.
Add the new column(s) to your table anyway you like, and then commit your changes to TFS. From there you can open the table's sql file in Visual Studio and manually move the order of the columns in the T-SQL CREATE script. Then you can update your target database by using VS's schema compare tool found under Tools > SQL Server > New Schema Comparison. Choose your Database project with your change as the source, and the database you want to update as the target. Compare, select the table's script, and Update. VS will drop and add automatically. All your data will be safe, and indexes too.
What i think is simple is to add the column ALTER TABLE table1 ADD .. and then create a tmp table like tmp_table1 from the select like
SELECT col1,col2,col5,col3,col4 into tmp_table1 from table1;
and then drop table1 and rename the tmp_table1 to table1, that is it. I hope it will help someone
Select all the columns into a temp table, and create a new table with the new column you want. Then drop the old table, select all the columns from the temp table, and insert them into the new table with the reordered column. No data is lost.
SELECT * FROM TEMP
SELECT * FROM originaltbl
SELECT * FROM #Stagintbl
DECLARE #ColumnName nvarchar(max);
SET #ColumnName=(SELECT
DISTINCT STUFF((
SELECT ',' + a.COLUMN_NAME
FROM (
SELECT Column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='originaltbl') a
for xml path('')
),1,1,'') AS ColumnName)
DECLARE #Sqlquery nvarchar(max)
SET #Sqlquery = 'SELECT ' + #ColumnName + ' FROM #Stagintbl' + '';
INSERT INTO originaltbl
EXECUTE(#Sqlquery)
Dirty and simple.
Export table to csv.
Insert new data at desired position.
Drop table.
Create new table with desired column specifications.
Load columns from csv to new table.
I am not sure if the thread is still active. I was having the same query with MySQL database. Right clicking the table and selecting 'ALTER' auto generated the below code. Sample provided from sakila db and it worked. Just find out the column after which you want to place your new column and use 'AFTER' keyword
ALTER TABLE `sakila`.`actor`
CHANGE COLUMN `middle_name` `middle_name` VARCHAR(50) NULL DEFAULT NULL AFTER `first_name`;

How do I add the identity property to an existing column in SQL Server

In SQL Server (in my case, 2005) how can I add the identity property to an existing table column using T-SQL?
Something like:
alter table tblFoo
alter column bar identity(1,1)
I don't beleive you can do that. Your best bet is to create a new identity column and copy the data over using an identity insert command (if you indeed want to keep the old values).
Here is a decent article describing the process in detail:
http://www.mssqltips.com/tip.asp?tip=1397
The solution posted by Vikash doesn't work; it produces an "Incorrect syntax" error in SQL Management Studio (2005, as the OP specified). The fact that the "Compact Edition" of SQL Server supports this kind of operation is just a shortcut, because the real process is more like what Robert & JohnFX said--creating a duplicate table, populating the data, renaming the original & new tables appropriately.
If you want to keep the values that already exist in the field that needs to be an identity, you could do something like this:
CREATE TABLE tname2 (etc.)
INSERT INTO tname2 FROM tname1
DROP TABLE tname1
CREATE TABLE tname1 (with IDENTITY specified)
SET IDENTITY_INSERT tname1 ON
INSERT INTO tname1 FROM tname2
SET IDENTITY_INSERT tname1 OFF
DROP tname2
Of course, dropping and re-creating a table (tname1) that is used by live code is NOT recommended! :)
Is the table populated? If not drop and recreate the table.
If it is populated what values already exist in the column? If they are values you don't want to keep.
Create a new table as you desire it, load the records from your old table into your new talbe and let the database populate the identity column as normal. Rename your original table and rename the new one to the correct name :).
Finally if the column you wish to make identity currently contains primary key values and is being referenced already by other tables you will need to totally re think if you're sure this is what you want to do :)
There is no direct way of doing this except:
A) through SQL i.e.:
-- make sure you have the correct CREATE TABLE script ready with IDENTITY
SELECT * INTO abcTable_copy FROM abcTable
DROP TABLE abcTable
CREATE TABLE abcTable -- this time with the IDENTITY column
SET IDENTITY_INSERT abcTable ON
INSERT INTO abcTable (..specify all columns!) FROM (..specify all columns!) abcTable_copy
SET INDENTITY_INSERT abcTable OFF
DROP TABLE abcTable_copy
-- I would suggest to verify the contents of both tables
-- before dropping the copy table
B) Through MSSMS which will do exactly the same in the background but will less fat-fingering.
In the MSSMS Object Explorer right click the table you need to modify
Select "design" Select the column you'd like to add IDENTITY to
Change the identity setting from NO -> YES (possibly seed)
Ctr+S the table
This will drop and recreate the table with all original data in it.
If you get a warning:
Go to MSSMS Tools -> Options -> Designers -> Table and database Designers
and uncheck the option "Prevent saving changes that require table re-creation"
Things to be careful about:
your DB has enough disk space before you do this
the DB is not in use (especially the table you are changing)
make sure to backup your DB before doing it
if the table has a lot of data (over 1G) try it somewhere else first
before using in real DB
Create a New Table
SELECT * INTO Table_New FROM Table_Current WHERE 1 = 0;
Drop Column from New Table
Alter table Table_New drop column id;
Add column with identity
Alter table Table_New add id int primary key identity;
Get All Data in New Table
SET IDENTITY_INSERT Table_New ON;
INSERT INTO Table_New (id, Name,CreatedDate,Modified)
SELECT id, Name,CreatedDate,Modified FROM Table_Current;
SET IDENTITY_INSERT Table_New OFF;
Drop old Table
drop table Table_Current;
Rename New Table as old One
EXEC sp_rename 'Table_New', 'Table_Current';
alter table tablename
alter column columnname
add Identity(100,1)

SQL Server how to drop identity from a column

Is there an easy way to remove an identity from a table in SQL Server 2005?
When I use Management Studio, it generates a script that creates a mirror table without the identity, copies the data, drops the table, then renames the mirror table, etc. This script has 5231 lines in it because this table/column have many FK relations.
I'd feel much more comfortable running a simple alter/drop. Any ideas?
EDIT
I think I'm just going to go with the 5,231 line script from Enterprise Manager. However, I'm going to break it up into smaller parts which I can run and control better. This table "behaves" strange, if you try to delete 1 row (even one you just inserted, which is not in any other FK table), you get this error:
delete MyTable where MyPrimaryKey=1234
Msg 8621, Level 17, State 2, Line 1
The query processor ran out of stack space during query optimization. Please simplify the query.
No doubt, all the FKs. We will halt all access to our application and run in single user mode when we make these schema and related application changes. However, we need this to run fast, and I need an idea of how long it will take. I guess that I'll just have to test, test, test.
If you are on SQL Server 2005 or later, you can do this as a simple metadata change (NB: doesn't require an edition supporting partitioning as I originally stated).
Example code pilfered shamelessly from the workaround by Paul White on this Microsoft Connect Item.
USE tempdb;
GO
-- A table with an identity column
CREATE TABLE dbo.Source
(row_id INTEGER IDENTITY PRIMARY KEY NOT NULL, data SQL_VARIANT NULL);
GO
-- Some sample data
INSERT dbo.Source (data)
VALUES (CONVERT(SQL_VARIANT, 4)),
(CONVERT(SQL_VARIANT, 'X')),
(CONVERT(SQL_VARIANT, {d '2009-11-07'})),
(CONVERT(SQL_VARIANT, N'áéíóú'));
GO
-- Remove the identity property
BEGIN TRY;
-- All or nothing
BEGIN TRANSACTION;
-- A table with the same structure as the one with the identity column,
-- but without the identity property
CREATE TABLE dbo.Destination
(row_id INTEGER PRIMARY KEY NOT NULL, data SQL_VARIANT NULL);
-- Metadata switch
ALTER TABLE dbo.Source SWITCH TO dbo.Destination;
-- Drop the old object, which now contains no data
DROP TABLE dbo.Source;
-- Rename the new object to make it look like the old one
EXECUTE sp_rename N'dbo.Destination', N'Source', 'OBJECT';
-- Success
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- Bugger!
IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;
PRINT ERROR_MESSAGE();
END CATCH;
GO
-- Test the the identity property has indeed gone
INSERT dbo.Source (row_id, data)
VALUES (5, CONVERT(SQL_VARIANT, N'This works!'))
SELECT row_id,
data
FROM dbo.Source;
GO
-- Tidy up
DROP TABLE dbo.Source;
I don't believe you can directly drop the IDENTITY part of the column. Your best bet is probably to:
add another non-identity column to the table
copy the identity values to that column
drop the original identity column
rename the new column to replace the original column
If the identity column is part of a key or other constraint, you will need to drop those constraints and re-create them after the above operations are complete.
You could add a column to the table that is not an identity column, copy the data, drop the original column, and rename the new column to the old column and recreate the indexes.
Here is a link that shows an example. Still not a simple alter, but it is certainly better than 5231 lines.

How do I alter a TEXT column on a database table in SQL server?

In a SQL server database, I have a table which contains a TEXT field which is set to allow NULLs. I need to change this to not allow NULLs. I can do this no problem via Enterprise Manager, but when I try to run the following script, alter table dbo.[EventLog] Alter column [Message] text Not null, I get an error:
Cannot alter column 'ErrorMessage' because it is 'text'.
Reading SQL Books Online does indeed reveal you are not allow to do an ALTER COLUMN on TEXT fields. I really need to be able to do this via a script though, and not manually in Enterprise Manager. What are the options for doing this in script then?
You can use Enterprise Manager to create your script. Right click on the table in EM and select Design. Uncheck the Allow Nulls column for the Text field. Instead of hitting the regular save icon (the floppy), click an icon that looks like a golden scroll with a tiny floppy or just do Table Designer > Generate Change Script from the menu. Save the script to a file so you can reuse it. Here is a sample script:
/* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_TestTable
(
tableKey int NOT NULL,
Description varchar(50) NOT NULL,
TextData text NOT NULL
) ON [PRIMARY]
TEXTIMAGE_ON [PRIMARY]
GO
IF EXISTS(SELECT * FROM dbo.TestTable)
EXEC('INSERT INTO dbo.Tmp_TestTable (tableKey, Description, TextData)
SELECT tableKey, Description, TextData FROM dbo.TestTable WITH (HOLDLOCK TABLOCKX)')
GO
DROP TABLE dbo.TestTable
GO
EXECUTE sp_rename N'dbo.Tmp_TestTable', N'TestTable', 'OBJECT'
GO
ALTER TABLE dbo.TestTable ADD CONSTRAINT
PK_TestTable PRIMARY KEY CLUSTERED
(
tableKey
) ON [PRIMARY]
GO
COMMIT
Create a new field. Copy the data across. Drop the old field. Rename the new field.
I think getting rid of the null values is the easist.
(as raz0rf1sh has said)
CREATE TABLE tmp1( col1 INT identity ( 1, 1 ), col2 TEXT )
GO
INSERT
INTO tmp1
SELECT NULL
GO 10
SELECT *
FROM tmp1
UPDATE tmp1
SET col2 = ''
WHERE col2 IS NULL
ALTER TABLE tmp1
ALTER COLUMN col2 TEXT NOT NULL
SELECT *
FROM tmp1
DROP TABLE tmp1
Off the top of my head, I'd say you need to create a new table with the same structure as the existing table but with your text column set to not null and then run a query to move the records from one to the other.
I realize that's sort of a pseudocode answer but I think that's really the only option you've got.
If others with a better grip on the exact TSQL syntax care to supplement this answer, feel free.
I would update all the columns with NULL values and set it to an empty string, for example, ''. Then you should be able to run your ALTER TABLE script with no problems. A lot less work than creating a new column.
Try to generate the change script from within Enterprise Manager to see how it is done there

Resources