Alter SQL Server table column width with indexes - sql

I am using SQL Server 2008 and need to alter a large number of columns across many tables from decimal(9,3) to decimal(12,6)
The issue I currently have is that some tables have several indexes on these columns and the alter statement fails due to the index.
Is there a way to alter the column without losing the index?
I am altering the column as follows:
alter table [TABLE_NAME] alter column [Conf_Tonnes] decimal(12,6) not null

I believe it is not possible to change the type of a column whilst it has any constraint on it. Certainly it used to be the case with earlier versions of SQL Server, and I don't think it has changed.
For practical purposes, you can use a script to list all fields of a certain type:
DECLARE #name AS varchar(20)
SET #name = '<Name of type>'
select T.name as "Table", F.name as "Field"
from sys.tables T left join sys.columns F on T.object_id=F.object_id
where F.user_type_id=(select user_type_id from sys.types where name=#name)
Which will give you the list of fields which need changing.
You can also drop constraints from fields but the difficult thing is how to recreate them.
if you have external meta-descriptions of the database, then you can use that to generate scripts easily. Alternatively, you could run the script generate tool - select all tables on, all options off, except tables and indexes - this should generate the full list of tables and indexes for you.
You can find it by right-clicking on the database in object explorer/tasks/generate scripts.
Unfortunately I don't think you can get index scripts generated without having table create scripts created as well - but Visual Studio text editing scripts shoudl make the job of cutting out the bits you don't want fairly easy.
Given time, it's probably possible to put together some scripts to do the whole job automatically, and it would give you a decent set of tools for future use.

Related

Copy Table Constraints/Keys along with Data and Structure

I have table "TableA", I want to make a copy of it "TableA_Copy", when I use the below script, it creates Table and data, but Constraints are not copied, is it possible copy the constraints along with Structure and Data
SELECT * INTO TableA_Copy FROM TableA
Note am using SQL Server 2016
Right click on the database and go to tasks->Generate script.
Select the table you want TableA, go to next step and ynder advanced options select data and schema.
Save the script or have it in a new query window.
Once the script is generated, replace TableA with TableA_copy
This way you will get data, schema and all the constraints. Remember to change the name of constraints to avoid any errors.
If you mean programmatically, then yes there are a number of ways in tsql to accomplish this by using the INFORMATION_SCHEMA views. The particular ones you will need for the table/columns are INFORMATION_SCHEMA.TABLES, and INFORMATION_SCHEMA.COLUMNS. For the constraints you can use INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE which will provide you the PK and FKs and INFORMATION_SCHEMA.CHECK_CONSTRAINTS for all check constraints.
Using these you can rebuild the table, complete, for use as you indicate above.

a special case when modifing the database

sometimes i face the following case in my database design,, i wanna to know what is the best practice to handle this case:::
for example i have a specific table and after a while ,, when the database in operation and some real data are already entered.. i need to add some required fields (that supposed not to accept null)..
what is the best practice in this situation..
make the field accept null as (some data already entered in the table ,, and scarify the important constraint )and try to force the user to enter this field through some validation in the code..
truncate all the entered data and reentered them again (tedious work)..
any other suggestions about this issue...
It depends on requirements. If the data to populate existing rows for the new column isn't available immediately then I would generally prefer to create a new table and just populate new rows when the data exists. If and when you have all the data for every row then put the new column into the original table.
If possible i would set a default value for the new column.
e.g. For Varchar
alter table table_name
add column_name varchar(10) not null
constraint column_name_default default ('Test')
After you have updated you could then drop the default
alter table table_name
drop constraint column_name_default
A lot will come down to your requirements.
It depends on your application, your database scheme, your entities.
The best way to go about it is to truncate the data and re - enter it again, but it need not be too tedious an item. Temporary tables and table variables could assist a great deal with this issue. A simple procedure comes to mind to go about it:
In SQL Server Management Studio, Right - click on the table you wish to modify and select Script Table As > CREATE To > New Query Editor Window.
Add a # in front of the table name in the CREATE statement.
Move all records into the temporary table, using something to the effect of:
INSERT INTO #temp SELECT * FROM original
Then run the script to keep all your records into the temporary table.
Truncate your original table, and make any changes necessary.
Right - click on the table and select Script Table As > INSERT To > Clipboard, paste it into your query editor window and modify it to read records from the temporary table, using INSERT .. SELECT.
That's it. Admittedly not quite straightforward, but a well - kept database is almost always worth a slight hassle.

How to alter a column from char(2) to varchar(5) on 1000 Tables in 100 Databases on 5 servers?

I need to come up with a script to alter a column from char(2) to varchar(5) on 1000 Tables in 100 Databases on 5 servers. The column will most probably have 'Office' in the name. However:
The column may have different name, not necessarily containing 'Office'.
Sometimes a column is indexed, sometimes not.
Sometimes a column is a Primary Key, sometimes not.
Sometimes there are computed columns, sometimes not.
Often there are many Views dependent on the above tables.
What would be the best methodology?
I started with Red Gate's Compare and Dependency Tracker, etc. but there are many independent tables where a column needs to be altered.
If you provide some more info I may be able to give a more specific answer. Maybe you could give a couple of examples of the different scenarios.
The generic answer is you need to find the different scenarios and work out how you'd do it manually. e.g. If it's just changing a column with no dependencies then you the ALTER TABLE will give you the right result. If you're not comfortable with building the SQL you can use the table designer in Management Studio and rather than saving the changes there is an option to generate the SQL.
Once you've got the sample SQL for each scenario then use the INFORMATION_SCHEMA tables to build up some SQL dynamically to find each scenario and build the correct ALTER TABLE as one of the columns. e.g.
select 'ALTER TABLE [' + table_schema + '].[' + table_name + '] ALTER COLUMN [' + column_name + '] varchar(5);' FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME like '%office%'
Because you're going across multiple databases and servers you may be able to use the sys.databases or sp_msforeachdb to apply to each database. To go across multiple servers you may be able to use linked servers or because there's only 5 you could just apply the same process 5 times.
hope that helps
SQL Prompt 5 will have a feature to identify column dependencies. It's currently in early access so if you sign up you can try out the feature and provide us with feedback.
For more details: http://www.red-gate.com/messageboard/viewtopic.php?t=11846
To sign up: http://www.surveymk.com/s/DZLN2JW
In the meantime you can always use the free SQL Search tool to find references to an object in your SQL Server schema: http://www.red-gate.com/products/SQL_Search/
Hope this helps!

Varchar(255) to Varchar(MAX)

Is it possible to change a column type in a SQL Server 2008 database from varchar(255) to varchar(MAX) without having to drop the table and recreate?
SQL Server Management Studio throws me an error every time I try to do it using that - but to save myself a headache would be nice to know if I can change the type without having to DROP and CREATE.
Thanks
You should be able to do it using TSQL.
Something like
ALTER TABLE [table] ALTER COLUMN [column] VARCHAR(MAX)
'Saving changes is not permitted. The
changes you have made require the
following tables to be dropped and
re-created. You have either made
changes to a table that can't be
re-created or enabled the option
Prevent saving changes that require
table to be re-created.' Option
'Prevent saving changes' is not
enabled..
That's a new "feature" in SQL Server Management Studio 2008 which by default is turned on. Whenever you make a larger change, SSMS can only recreate the table by creating a new one and then moving over the data from the old one - all in the background (those changes include re-ordering of your columns amongst other things).
This option is turned off by default, since if your table has FK constraints and stuff, this way of re-doing the table might fail. But you can definitely turn that feature on!
It's under Tools > Options and once you uncheck that option you can do these kind of changes to table structure in the table designer again.
Be aware
with Something like
ALTER TABLE [table] ALTER COLUMN [column] VARCHAR(MAX)
https://dba.stackexchange.com/questions/15007/change-length-of-varchar-on-live-prod-table
Martin Smith's answare:
If you are increasing it to varchar(100 - 8000) (i.e. anything other than varchar(max)) and you are doing this through TSQL rather than the SSMS GUI ALTER TABLE YourTable ALTER COLUMN YourCol varchar(200) [NOT] NULL and not altering column nullability from NULL to NOT NULL (which would lock the table while all rows are validated and potentially written to or from NOT NULL to NULL in some circumstances then this is a quick metadata only change. It might need to wait for a SCH-M lock on the table but once it acquires that the change will be pretty much instant.
One caveat to be aware of is that during the wait for a SCH-M lock other queries will be blocked rather than jump the queue ahead of it so you might want to consider adding a SET LOCK_TIMEOUT first.
Also make sure in the ALTER TABLE statement you explicitly specify NOT NULL if that is the original column state as otherwise the column will be changed to allow NULL.

Re-runnable SQL Server Scripts

What are the best practices for ensuring that your SQL can be run repeatedly without receiving errors on subsequent runs?
e.g.
checking that tables don't already exist before creating them
checking that columns don't already exist before creating or renaming
transactions with rollback on error
If you drop tables that exist before creating them anew, drop their dependencies first too, and don't forget to recreate them after
Using CREATE OR ALTER PROCEDURE instead of CREATE PROCEDURE or ALTER PROCEDURE if your flavor of SQL supports it
Maintain an internal versioning scheme, so the same SQL just doesn't get run twice in the first place. This way you always know where you're at by looking at the version number.
Export the existing data to INSERT statements and completely recreate the entire DB from scratch.
dropping tables before creating them (not the safest thing ever, but will work in a pinch if you know what you're doing)
edit:
I was looking for something like this:
IF EXISTS ( SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[foo]')
AND OBJECTPROPERTY(object_id, N'IsUserTable') = 1 )
DROP TABLE foo
Do others use statements like this or something better?
edit:
I like Jhonny's suggestion:
IF OBJECT_ID('table_name') IS NOT NULL DROP TABLE table_name
I do this for adding columns:
IF NOT EXISTS ( SELECT *
FROM SYSCOLUMNS sc
WHERE EXISTS ( SELECT id
FROM [dbo].[sysobjects]
WHERE NAME LIKE 'TableName'
AND sc.id = id )
AND sc.name = 'ColumnName' )
ALTER TABLE [dbo].[TableName] ADD [ColumnName]
To make things easier I configure management studio to script objects as rerunnable
Tools
Options
SQL Server Object Explorer
Scripting
Object scripting options
Include IF Not Exists Clause True
I think the most important practice in ensuring that your scripts are re-runnable is to....run them against a test database multiple times after any changes to the script. The errors you encounter should shape your practices.
EDIT
In response to your edit on syntax, in general I think it is best to avoid the system tables in favor of the system views e.g.
if exists(Select 1 from information_schema.tables where table_name = 'sometable')
drop sometable
go
if exists(Select 1 from information_schema.routines where
specific_name = 'someproc')
drop someproc
To add to your list:
If you drop tables that exist before creating them anew, drop their dependencies first too, and don't forget to recreate them after
Using CREATE OR ALTER PROCEDURE instead of CREATE PROCEDURE or ALTER PROCEDURE if your flavor of SQL supports it
But ultimately, I would go with one of the following:
Maintain an internal versioning scheme, so the same SQL just doesn't get run twice in the first place. This way you always know where you're at by looking at the version number.
Export the existing data to INSERT statements and completely recreate the entire DB from scratch.
I recently found a check-in for existence that i didn't know existed and i liked it because it's shorter
IF OBJECT_ID('table_name') IS NOT NULL DROP TABLE table_name
before, i used to use
IF EXISTS (SELECT * FROM information_schema.tables WHERE table_name = 'table_name')
DROP TABLE table_name
Which i found useful because it's a little more portable (MySql, Postgres, etc), taking into account the differences, of course
For maintaining schemas, look at a migration tool. I think LiquiBase would work for SQL Server.
You'll also need to check for foreign keys on any tables that you may be dropping/recreating. Also, consider any data changes that you might make - delete rows before trying to insert a second time, etc.
You also might want to put in code to check for data before deleting tables as a safeguard so that you don't drop tables that are already being used.
For a SQL batch statement, you can issue
This is just a FYI, I just ran it 10 times
IF EXISTS ( SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[foo]')
AND OBJECTPROPERTY(object_id, N'IsUserTable') = 1 )
DROP TABLE foo
GO 10 -- run the batch 10 times
This is just a FYI, I just ran it 10 times
Beginning execution loop Batch
execution completed 10 times.
The "IF OBJECT_ID('table_name', 'U') IS NOT NULL" syntax is good, it can also be used for procedures:
IF OBJECT_ID('procname', 'P') IS NOT NULL
...
... and triggers, views, etc... Probably good practice to specify type (U for table, P for prog, etc.. dont remember the exact letters for all types) in case your naming strandards allow procedures and tables to have similar names...
Furthermore, a good idea might be to create your own procedures that changes tables, with error handling proper to your environment. For example:
prcTableDrop, Proc for droping a
table
prcTableColumnAdd, Proc for adding a column to a table
prcTableColumnRename, you get the idea
prcTableIndexCreate
Such procs makes creating repeatable (in same or other db) change scripts much easier.
/B
I've describe a few checks in my post DDL 'IF not Exists" conditions to make SQL scripts re-runnable
Just adding this for future searchers (including myself), such scripts are called idempotent (the noun being idempotency)