How can I create a File Group on a different drive with MSSQL 2005 and then move a table into it?
Ex: my database is on H:\Product.mdf and H:\Product.ldf
I want to create a new file group on F:\FileGroup\ and then move my table with a clustered index to this new file group.
This is not a simple task, and depending on the size of your tables may require a chunk of downtime.
First, you have to define the new file group:
ALTER DATABASE MyDatabase
add filegroup NewGroup
Then, create an appropriate file for that file group, for example:
ALTER DATABASE MyDatabase
add file
(
name = NewFile
,filename = 'C:\temp\NewFile.ndf'
,size = 100MB
,maxsize = unlimited
,filegrowth = 100MB
)
to filegroup NewGroup
To move a table onto the file group, you have to create a clustered index for that table on the file group. If you've got a clustered constraint (such as a unique or primary key), you'll have to drop it first. Here's one way to move such a table:
-- Set up sample table
CREATE TABLE MyTable
(
Data varchar(100) not null
constraint PK_MyTable
primary key clustered
)
-- Can't "move" primary key constraint to a new file group
ALTER TABLE MyTable
drop constraint PK_MyTable
-- This will move the data in the table to the new file group
CREATE clustered index Move_MyTable
on MyTable (Data)
on NewGroup
-- Still in the new file group, just no index
DROP INDEX MyTable.Move_MyTable
-- Recreate the primary key, keeping it on the new file group
ALTER TABLE MyTable
add constraint PK_MyTable
primary key clustered (Data)
on NewGroup
It is just a bit fussy, so be sure to test everything on copies of your databases first!
Related
I have the following (simplified) structure of a device and log messages which are attached to a device:
CREATE TABLE device (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
serial_number VARCHAR(20) UNIQUE
);
CREATE TABLE error_log (
id SERIAL PRIMARY KEY,
device_id INT NOT NULL REFERENCES device(id),
);
I know want to change the schema to use the serial_number column of the device as the primary key, and drop the automatic key id. As part of the process I need to add a new column device_serial_number to the error_log table. My question is how to assign the values to this column using only SQL.
If a had an ORM mapper in action my pseudo code would look like this:
for log in error_log.all_objects():
log.device_serial_number = log.device.serial_number
Can I do this in pure SQL? (Postgresql if that matters)
You need to update the rows in the error_log table where the device.id = error.log match to device.serial_number.
So, first add a column to error_log. And then execute an UPDATE statement as following:
update error_log
set serial_number = d.serial_number
from device d
where error_log.id = d.id;
Afterwards you should add a UNIQUE constraint to the error_log.serial_number and then you can remove the error_log.device_id column if you don't need it anymore.
This is doable, just not in a single step.
add the new column to the error_log table. This must be nullable for now!
alter table error_log
add device_serial_number varchar(20);
Populate the new column with the correct values
update error_log
set device_serial_number = d.serial_number
from device d
where error_log.device_id = d.id;
Now the new column can be set to NOT NULL and we can remove the existing foreign key.
alter table error_log
alter column device_serial_number set not null,
drop constraint error_log_device_id_fkey;
Now drop the ID column, drop the old unique constraint and define a new primary key. Dropping the old unique constraint will remove the underlying unique index which is no longer needed as the primary key will create a new one.
alter table device
drop column id,
drop constraint device_serial_number_key,
add primary key (serial_number);
-- re-create the foreign key to the new primary key
alter table error_log
drop column device_id,
add foreign key (device_serial_number)
references device(serial_number);
Note that the drop constraint error_log_device_id_fkey and drop constraint device_serial_number_key assume the default naming convention that Postgres applies for "unnamed" constraints. You need to check if that really is the name of your foreign key.
I create a draft database with 2 tables: dbo.D and dbo.F, next I create a new filegroup for dbo.F and a file for this.
USE DEV
ALTER DATABASE DEV
ADD FILEGROUP [BLOB]
ALTER DATABASE DEV
ADD FILE
(
NAME= 'blob',
FILENAME = 'D:\MS SQL\DB\blob.mdf'
)
TO FILEGROUP [BLOB]
Next, I drop clustered index and recrete it, specifying a filegroup name.
ALTER TABLE F
DROP CONSTRAINT [F_PK] WITH (MOVE TO BLOB)
ALTER TABLE F
ADD CONSTRAINT [F_PK] PRIMARY KEY CLUSTERED
(
ID
)
WITH (IGNORE_DUP_KEY = OFF) ON BLOB
CREATE UNIQUE CLUSTERED INDEX F_PK
ON dbo.F(ID)
WITH DROP_EXISTING
ON [BLOB]
Next, I create more then 2k INSERT's queries and full in dbo.F with random binary data.
Question!
Why on this picture my new filegroup's file weighs so little unlike in the default filegroup's file?
Without seeing the full schema of your tables... you only have ID in your clustered index which means that all of the data you inserted is still in your primary filegroup. The only thing in blob is the index of your ID values which I would assume is not going to be anywhere near as large as the binary data you are inserting. I'm basing my assumption on ID being an INT column...
This, of course, is irrelevant if ID is the column in which you are storing your binary data, but I assume that's not the case if you're using it as a PK and clustered index.
I am working on SQL Server 2012:
I have a table with a primary key column as INT. I need to change this to a GUID.
Do I alter the table and remove int column as primary key?
Add the GUID column and set it as Primary and drop the old INT column?
Thank you.
You can't change primary key column,unless you drop it..Any operations to change its data type will lead to below error..
The object 'XXXX' is dependent on column 'XXXX'.
Only option is to
1.Drop primary key
2.change data type
3.recreate primary key
ALTER TABLE t1
DROP CONSTRAINT PK__t1__3213E83F88CF144D;
GO
alter table t1
alter column id varchar(10) not null
alter table t1 add primary key (id)
From 2012,there is a clause called (DROP_EXISTING = ON) which makes things simple ,by dropping the clustered index at final stage and also keeping old index available for all operations..But in your case,this clause won't work..
So i recommend
1.create new table with desired schema and indexes,with different name
2.insert data from old table to new table
3.finally at the time of switch ,insert data that got accumulated
4.Rename the table to old table name
This way you might have less downtime
You can change the date type of the primary key in three steps
Step 1 :- Drop the constraint associated with the Primary key
ALTER TABLE table_name
DROP CONSTRAINT constraint_name;
Step 2 :- Alter the Primay key column to a valid primary key data type
ALTER TABLE table_name
ALTER COLUMN pk_column_name target_data_type(size) not null;
Step 3 :- Make the altered column primary key again
ALTER TABLE table_name
ADD PRIMARY KEY (pk_column_name);
PS :-
You can get the Constraint name from the error message when you try to alter the
pk_column
If you already have data in the pk_column make sure the source and target data type of the column both can be used for the existing data. else another two steps would be needed to move the existing data to a temporary column and then perform the steps and bring back that data after vetting and dropping that temporary column.
Below is a script I wrote to help us deploy a change to primary key column data type.
This script assumes there aren't any non-primary key constraints (e.g. foreign keys) depending on this column.
It has a few safety checks as this was designed to be deployed to different servers (dev, uat, live) without creating side effects if the table was somehow different on a server.
I hope this helps someone. Please let me know if you find anything wrong before down-voting. I'm more than happy to update the script.
IF EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS C WITH (NOLOCK) WHERE C.TABLE_CATALOG = '<<DB>>' AND C.TABLE_SCHEMA = 'dbo' AND C.TABLE_NAME = '<<Table>>'
AND C.COLUMN_NAME = '<<COLUMN>>' AND C.DATA_TYPE = 'int') -- <- Additional test to check the current datatype so this won't make unnecessary or wrong updates
BEGIN
DECLARE #pkName VARCHAR(200);
SELECT #pkName = pkRef.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pkRef WITH (NOLOCK)
WHERE pkRef.TABLE_CATALOG = '<<DB>>' AND pkRef.TABLE_SCHEMA = 'dbo' AND TABLE_NAME = '<<Table>>'
IF(#pkName IS NOT NULL)
BEGIN
-- Make sure the primary key name is the one you are going to use in script beyond this point.
IF(#pkName != '<<PRIMARY KEY NAME>>')
BEGIN
RAISERROR ('Unexpected primary key name - The primary key found has a different name than expected. Please update the script.', 16, 1);
RETURN;
END
ALTER TABLE dbo.<<Table>>
DROP CONSTRAINT <<PRIMARY KEY NAME>>; -- Note: this is not a string or a variable (just type the PK name)
SELECT 'Dropped existing primary key';
END
ALTER TABLE dbo.<<Table>> ALTER COLUMN ID BIGINT
SELECT 'Updated column type to big int';
ALTER TABLE dbo.<<Table>>
ADD CONSTRAINT <<PRIMARY KEY NAME>> PRIMARY KEY CLUSTERED (<<COLUMN>>);
SELECT 'Created the primary key';
END
ELSE
BEGIN
SELECT 'No change required.';
END
In case other tables reference your PK with indexed FK's, these are the steps you must follow.
In this example, the main table's called Main, the single referencing table Reference. I'm changing the datatype to NVARCHAR(7). To use it:
Find/replace all these table names with your own;
Modify the data type;
You might also need to separately find/replace the dbo schema;
I'm using syntax which includes constraint names - if you want, also update these to your preferred naming conventions.
ALTER TABLE dbo.Main ADD IdNew NVARCHAR(7);
UPDATE dbo.Main SET IdNew = Id;
-- For all tables with FK's to this Main:
ALTER TABLE dbo.Reference ADD MainIdNew NVARCHAR(7);
UPDATE dbo.Reference SET MainIdNew = MainId;
ALTER TABLE dbo.Reference DROP CONSTRAINT FK_Reference_MainId_Main_Id;
DROP INDEX IX_Reference_MainId ON dbo.Reference;
ALTER TABLE dbo.Reference DROP COLUMN MainId;
-- Until here
ALTER TABLE dbo.Main DROP CONSTRAINT PK_Main;
ALTER TABLE dbo.Main DROP COLUMN Id;
EXEC sp_rename 'dbo.Main.IdNew', 'Id', 'COLUMN';
ALTER TABLE dbo.Main ALTER COLUMN Id NVARCHAR(7) NOT NULL;
ALTER TABLE dbo.Main ADD CONSTRAINT PK_Main PRIMARY KEY (Id);
-- Again for all tables with FK's to this Main:
EXEC sp_rename 'dbo.Reference.MainIdNew', 'MainId', 'COLUMN';
ALTER TABLE dbo.Reference ADD CONSTRAINT FK_Reference_MainId_Main_Id FOREIGN KEY (MainId) REFERENCES dbo.Main(Id);
CREATE INDEX IX_Reference_MainId ON dbo.Reference(MainId);
Right in the table you want to change the PK type >> Modify. Go in the column, change the type and save. If you want to see the code for such a change, before saving, you can right-click >> "Generate Change Script ..".
Using Microsoft SQL Server Management Studio do the following:
Open table Design
Change the primary key column type or any other change which is also possible with this way
Right click on the design area and select Generate Change Script
Accept Validation Warning
Preview changes or save them in file.
Profit :)
This works for any change to the table, just bare in mind that SSMS creates a temporary second table to do the difficult changes like primary column type change.
This works for me in version 18.9 of the app.
I have a table which includes an identity column but i cant remove the identity property.
Is there a way to disable it? Or a way to make a copy of the entire table without identity property?
Note that you may not be able to drop the column if it referenced by a clustered index, and you can't drop all clustered indexes for a table because SqlAzure tables must always have a clustered index.
This means that you may have to jump through the following hoops (for at least your last clustered index, which may well be your primary key):
rename your clustered index
create a temp version of the table (with a new clustered index)
copy the data from the current table
drop the current table
rename the temp table to the current name
This roughly looks like this:
-- Rename clustered index
EXECUTE sp_rename N'PK_My_Current_PK', N'PK_My_Current_PK_OLD', 'OBJECT'
-- If you have any FK constraints on the table, then drop them
ALTER TABLE dbo.MyTable DROP CONSTRAINT FK_My_Foreign_Key
-- Create the new version of your table - because this is SQLAzure it must have a clustered index
CREATE TABLE dbo.tmp_MyTable (
MyID int NOT NULL,
CONSTRAINT PK_My_Current_PK PRIMARY KEY CLUSTERED (MyID)
)
-- Copy the data into the temp table from the old table
INSERT INTO dbo.tmp_MyTable (MyID)
SELECT MyID FROM dbo.MyTable
-- Drop the old table
DROP TABLE dbo.MyTable
-- Rename the new table
EXECUTE sp_rename N'tmp_MyTable', N'MyTable', 'OBJECT'
-- Recreate any foreign key constraints
ALTER TABLE dbo.MyTable WITH CHECK ADD FK_My_Foreign_Key FOREIGN KEY (MyID)
REFERENCES dbo.MyForeignTable (MyID)
Hope that helps
A
Edit: As #PhilBolduc pointed out SqlAzure tables require a clustered index, not a primary key. I've amended the terminology above accordingly - the principle of the answer still remains.
You can not remove an Identity column without dropping it unfortunately. Alternetivly add a new column with a temp name, update the new column value and then drop the previous column.
ALTER TABLE dbo.tablename ADD newcolumnname INT
UPDATE dbo.tablename SET newcolumnname = oldcolumnname FROM dbo.tablename
ALTER TABLE dbo.tablename DROP COLUMN oldcolumnname
that should do it. unless i have misunderstood your questions?
I wrote a script that creates some tables (it previously drops them if they exist) and then tries to create two indexes on each table.
The first index uses the Primary Key column to create a non-clustered index, and the second uses another column to create the clustered indexed. This is because the primary key column is a GUID instead of an int.
How can I drop the default index if I don't know it's name? or how can I specify a name for the primary key column index so I can drop it? Or better yet, how can I specify the 2 index i need right in the Create Table statement?
SELECT * FROM sys.indexes
However, I'm not understanding where in your process you actually have to drop an index.
You said you are creating some tables and then creating two indexes on each table.
If you are DROPping existing tables at the beginning, any indexes are automatically dropped.
There is no such thing as a default index.
Tables can either be heaps or clustered indexes. If you drop the clustered index, the table will be converted to a heap and any non-clustered indexes will have to be updated to point to the data in the unordered heap.
You can create like this all at once:
CREATE TABLE dbo.tbl
(
Id int NOT NULL IDENTITY (1, 1) CONSTRAINT UK_ID UNIQUE CLUSTERED,
SomeUUID UNIQUEIDENTIFIER NOT NULL CONSTRAINT PK_SomeUUID PRIMARY KEY NONCLUSTERED
)
Here's a SQLFiddle: http://sqlfiddle.com/#!6/d759e/12
You can define the two indices right after you create the table:
CREATE TABLE dbo.YourTable ( ...... )
GO
ALTER TABLE dbo.YourTable
ADD CONSTRAINT PK_YourTable PRIMARY KEY NONCLUSTERED (YourGuidColumn)
****************
this is crucial ! Otherwise, your PK will be clustered!
CREATE CLUSTERED INDEX IX01_YourTable ON dbo.YourTable(YourOtherColumn)
or even better:
CREATE UNIQUE CLUSTERED INDEX IX01_YourTable ON dbo.YourTable(YourOtherColumn)
That should create a non-clustered primary key and a separate (preferably unique) clustered index on a separate column.