Changing table with dependent index - sql-server

As part of a system upgrade, we need to be able to update a database structure to conform to the newest version.
I'm writing a tool to that end, but am stuck on the correct procedure for updating a column which is used in an index.
If a column which is in an index must be changed, which approach is likely to be the least problematic:
1) Disable the index, alter the column, re-enable the index
2) Drop the index, alter the column, re-create the index
There are a number of instances where this change must be applied, and I would like to reduce the overall time as much as possible, hence my preference for not recreating the index if it can be avoided.

I did some tests,it seems you cannot alter index columns .
test data:
create table idd
(
id int identity(1,1),
name char(33),
name2 varchar(40) null
)
create unique clustered index nci_id on idd(id)
create index nci_test1 on idd(name2)
--disable index
alter index nci_test1 on idd disable
--alter column
alter table idd
alter column test1 varchar(100) not null
below is the error:
Msg 5074, Level 16, State 1, Line 36
The index 'nci_test1' is dependent on column 'test1'.
Msg 4922, Level 16, State 9, Line 36
ALTER TABLE ALTER COLUMN test1 failed because one or more objects access this column.
This is obvious since I have clustered key.so what happens if I drop clustered key and then do an alter operation on non clustered index key column,Result is same.We can alter index columns only after dropping them
drop index [nci_id] on idd
--alter column
alter table idd
alter column test1 varchar(100) not null
I think you got some idea on what is the impact
1.We have to drop clustered key first ..heavy tlog writes,since non clustered key also have to change there pointers
2.Again we have to rebuild indexes
You can only drop them.Further I would suggest you go ahead with this approach(since either way you have to drop clustered index) of
1.Drop index
2.Alter column datatype
3.recreate index
Further try changing database recovery model to simple,so as to minimize TLOG writes prior to this operation and also add nocheck option .Below questions has some interesting answers which may help you
https://dba.stackexchange.com/questions/48872/quickly-change-null-column-to-not-null
How do you add a NOT NULL Column to a large table in SQL Server?

Related

SQL Server Automatic Index Changes (A filter on my index is gone)

I'm using SQL Server 2008
I know that an index on a view will be deleted without prejudice nor warning if you change the view definition. I am wondering if there are any other known similar automatic changes to indexes and if so where can I read about them?
My situation:
I had a unique non-clustered filtered index on a table.
The index key columns are the same as the primary key of the table.
Only one other column is included.
Today I when things were going slowly, I realized that the filter is now gone.
One of the primary key column types was recently changed to a different type. So I'm guessing that may have been when the filter removal happened, but I can't find verification of that anywhere.
If it helps, I could not simply add the filter back because when trying to recreate, 'The new index definition does not match the constraint being enforced by the existing index.'
Neither can I simply drop the index to recreate it because apparently SQL Server decided to use the index to enforce foreign key constraints instead of the clustered PK index. I will have to delete foreign key constraints before I do.
All of our devs said that they didn't mess with the index. One of us may be forgetful. Or lying. Or someone may have changed something and not have read very carefully the warning messages. I don't know if this is something that could be automatic so I'm hoping you guys can inform me.
Thanks!
I guess someone is fishing :)
Here's test code which shows that you can't change PK's column data type without dropping indexes off first:
create table dbo.worker
(
id int identity not null constraint PK_worker primary key,
name varchar(100) not null
);
-- Filtered index based in PK's primary index
create nonclustered index ix_worker
on dbo.worker (id)
where id < 3;
-- Try to change PK's column data type...
alter table dbo.worker
alter column id bigint;
SQL Server generates following errors:
Msg 5074, Level 16, State 1,
Line 8 The index 'ix_worker' is dependent on column 'id'.
Msg 5074, Level 16, State 1, Line 8
The object 'PK_worker' is dependent on column 'id'.
Msg 5074, Level 16, State 1, Line 8
The index 'ix_worker' is dependent on column 'id'.
Msg 4922, Level 16, State 9, Line 8
ALTER TABLE ALTER COLUMN id failed because one or more objects access this column.

SQL Server - ALTER TABLE ALTER COLUMN giving SET option error

I am trying to change datatype of a column in SQL Server from INT to BIGINT.
ALTER TABLE Table1 ALTER COLUMN ID BIGINT
However, it is giving me below error:
ALTER TABLE failed because the following SET options have incorrect settings: 'ANSI_WARNINGS'. Verify that SET options are correct for use with indexed views and/or indexes on computed columns and/or filtered indexes and/or query notifications and/or XML data type methods and/or spatial index operations.
I checked the Table1 and there is just 1 computed column (i.e. cost * quantity kind off). There are no indexes on this particular column. Neither there is any index on ID column. The ID column of Table1 is not referred elsewhere in any other table. I tried changing ANSI_Warnings ON and OFF but still gives same error.
So I am not sure where the problem is. Any help appreciated!
I was doing the same thing the OP - alter the PK from INT to BIGINT on 2 tables. In first table it went smoothly, in second table I got same error as OP:
ALTER TABLE failed because the following SET options have incorrect
settings: 'ANSI_WARNINGS'. Verify that SET options are correct for use
with indexed views and/or indexes on computed columns and/or filtered
indexes and/or query notifications and/or XML data type methods and/or
spatial index operations.
Running SET ANSI_WARNINGS ON or OFF is not helping.
The steps are:
drop indexes
drop PK constraint
drop persisted columns
run ALTER TABLE [table] ALTER COLUMN [id] BIGINT
create persisted columns, indexes, PK constraint back as they were
To get rid of the error, there's one thing I had to do differently in step 1:
in first table it was OK to drop just indexes using the changed column, keep other indexes
in second table I had to drop all indexes, even those not using the column
Probably because your column is the Primary Key and indexed as the CLUSTERED index, then used by every NONCLUSTERED indexes...
So drop NONCLUSTERED indexes and the PK, execute the ALTER TABLE and then add the PK and all NONCLUSTERED indexes that you have dropped.

Can i drop a column of a table in SQL server which is having a non clustered index defined on it

I have a table with huge record count . Some of the columns have a non clustered indexes defined on them .
we are required to alter/drop few columns which are having such indices defined.
I have directly alter/dropped the columns , but did not get any error like :
Alter statement failed . It succeeded. So , here is my question is :
Is it required to drop non clustered indexes on the columns which are going to be dropped/altered ?
why it did give any errors similar to case of constraints/keys defined on them ?
Updated :
What incase of alteting a column for its size ? Is it supposed to throw any error ?
Your question is worded kind of strangely to me and I'm having trouble following exactly what you're asking... but this is easy enough to test yourself.
You cannot drop a column that has an index, see:
CREATE TABLE tempThing (id int IDENTITY(1,1) PRIMARY key, someValue varchar(50))
GO
CREATE INDEX idxTemp ON dbo.tempThing (someValue)
GO
Then:
ALTER TABLE dbo.tempThing DROP COLUMN someValue
Gives error:
Msg 5074, Level 16, State 1, Line 1
The index 'idxTemp' is dependent on column 'someValue'.
Msg 4922, Level 16, State 9, Line 1
ALTER TABLE DROP COLUMN someValue failed because one or more objects access this column.
I just tried this:
create table #t1(i1 int, i2 int)
create index a1 on #t1(i1)
alter table #t1 drop column i1
failed
with the message
alter table drop column i1 failed because one or more objects access this `column.
Are you sure you had indexes that referred to those dropped column and they were dropped successfully?

Change datatype of a column and set a column as identity in SQL

----------------------------------------------
DepartmentCode varchar(30) AllowNulls
----------------------------------------------
Does anyone know how to change the datatype of a column in SQL 2008? This is the column I want to alter but when I try this query,
ALTER TABLE SystemDepartment ALTER COLUMN DepartmentCode smallint NOT NULL
I get the following error:
Msg 5074, Level 16, State 1, Line 1
The object 'PK_SystemDepartment' is dependent on column
'DepartmentCode'. Msg 4922, Level 16, State 9, Line 1 ALTER TABLE
ALTER COLUMN DepartmentCode failed because one or more objects access
this column.
My question is how to force my query to cope with it? and I also would like to set this column as primary key and identity
You will first need to drop Primary Key constraint.
ALTER TABLE SystemDepartment DROP CONSTRAINT PK_SYSTEMDEPARTMENT
Then only you can ALTER that column.
You can not force existing column to identity. In this case you will need to add new column with identity and then do sp_rename to old name.
If your constraint is on a user type, then don't forget to see if there is a Default Constraint, usually something like DF__TableName__ColumnName__6BAEFA67, if so then you will need to drop the Default Constraint, like this:
ALTER TABLE TableName DROP CONSTRAINT [DF__TableName__ColumnName__6BAEFA67]
For more info see the comments by the brilliant Aaron Bertrant on this answer.
Try this ,
as you told you are getting primary key constraint error , 1st you have to drop the primary key and use the following query ,
ALTER TABLE SystemDepartment MODIFY DepartmentCode int(3)
Thanks,
Venkat.

Create PK for #temp table failed when the script is run in parallel

I have the following code in a stored procedure.
....
select ... into #temp from ....
alter table #temp add constraint PK_mytemp13 primary key (....)
....
And I will get the following error message from time to time if the stored procedure is run in parallel.
There is already an object named 'PK_perf322dsf' in the database.
Could not create constraint. See previous errors.
I think it can be avoid by the following approaches. Is there any other more elegant solution?
Create a temp table with primary key first. Then insert the rows.
create table #temp (... primary key (....))
Create PK dynamically with session id dynamically.
declare #s varchar(500) = 'alter table #temp add constraint PK_temp' + ##spid + ' primary key (....)
This can only happen if the same client connection instantiation (which equals one SPID or connection in SQL Server) is being re-used for 2 different calls. Two parallel calls should have different connection instantiations and separate SPIDs
SPIDs are completely isolated from each other with local (single #temp tables)
Edit:
Ignore above
I've never named constraints on temp tables before. I use indexes as I need them or just add PRIMARY KEY after the column. Constraint names are database-unique in sys.objects
A PK is basically a non-unique clustered index. So use CREATE UNIQUE CLUSTERED INDEX instead as index names are unique per table in sys.indexes.
This fails when run in 2 SSMS Query windows
CREATE TABLE #gbn (foo int NOT NULL);
ALTER TABLE #gbn ADD CONSTRAINT PK_gbn PRIMARY KEY (foo);
Msg 2714, Level 16, State 5, Line 2
There is already an object named 'PK_gbn' in the database.
Msg 1750, Level 16, State 0, Line 2
Could not create constraint. See previous errors.
Curiously, the error and the constraint name match unlike your error
This works
CREATE TABLE #gbn (foo int NOT NULL);
CREATE UNIQUE CLUSTERED INDEX PK_gbn ON #gbn (foo);
I was trying to remember how to do this, but you can create a nameless primary key on a temp table and avoid this error. This is different than putting a column-level PK, as it supports more than 1 column. Here is an example:
CREATE TABLE #test
(
AccountNumber INT NOT NULL,
TransactionNumber INT NOT NULL,
PRIMARY KEY CLUSTERED (tranid, sys_process_dt)
);
This allows the end goal plus prevents name duplication. Querying will show that SQL Server will put a GUID in the name of the PK for you in sys.sysobjects:
SELECT *
FROM tempdb.sys.sysobjects
WHERE name LIKE '%#test%'
name | xtype
--------------------------------
#test___..._000000000407 | U
PK__#test_____B88A05A770B3A6A6 | PK
You can have your cake and eat it too.
you try to insert to the same temporary table from different connections (which is impossible, instead of global temp tables),
or you try to insert into different tables.
if 2nd - you simply may do the following - ALTER TABLE #temp ADD PRIMARY KEY(...)
if 1st - you have to create the table (regular or global temporary) with key prior to use it in parallel operations
I know this has been answered and accepted but still did not see the correct point has been call out.
when you create Named constraint, name of the constraint has to be precise at table level. they are scoped at database level. so either do not create named constrained and let sql pick its own name or if you give name make sure it s unique in that DB. even for TEMP DB.
Even more to the point, ANY named constraint on a temp table must be uniquely named across sessions. This also means that a default constraint (say you're setting a field to default to a value of -1) and that default constraint is explicitly named, SQL Server will throw an error when you attempt to create a temp table in another session window even though it's not a key constraint.
For example, open two query windows and run the following code in one and then the other (without closing either window first):
DROP TABLE IF EXISTS #TempTbl1;
CREATE TABLE #TempTbl_1 (
[TestCol1] INT
,[TestCol2] BIGINT CONSTRAINT [DF_Tc2] DEFAULT (-1)
);
The first window will execute fine, but the second will throw an error stating
Msg 2714, Level 16, State 5, Line 2
There is already an object named 'DF_Tc2' in the database.
Msg 1750, Level 16, State 1, Line 2
Could not create constraint or index. See previous errors.
This is in spite of the fact that the table has no PKs or indexes, just a named default constraint.

Resources