SQL 2005: How to add same column and FK across multiple tables - sql

I need to add a Column "CurrentLifeCycleId" [int] into 73 tables and also add a Foreign Key from this new column to another single table "LifeCycle" Id column...is there a simple way I can do this in a few statements rather than go through each table one by one.
The column does not need to start off being NULL as I will delete all records from these tables before I start.
It's the weekend and I don't want to spend all today doing this :)
Thanks in advance.

Use SQL to built a script:
SELECT N'ALTER TABLE ' +quotename(name)+N' ADD COLUMN CurrentLifeCycleId (int) null;
alter table '+quotename(name)+N' ADD CONSTRAINT fk_LifeCycleId
(CurrentLifeCycleId ) references other_table (LifeCycleId);
'
FROM sys.tables where name in ('table1', 'table2', ..., 'table73');
Press Ctrl-T to push have results as text, execute in SSMS, select the result and paste it into a new query window. There are fabcier ways (like PowerShell), but this is fairly easy and straight forward. If the tables ar ein differnet schema, make sure you add that too into the script output.
Also make sure the script is correct before running it :)

Related

Adding Row in existing table (SQL Server 2005)

I want to add another row in my existing table and I'm a bit hesitant if I'm doing the right thing because it might skew the database. I have my script below and would like to hear your thoughts about it.
I want to add another row for 'Jane' in the table, which will be 'SKATING" in the ACT column.
Table: [Emp_table].[ACT].[LIST_EMP]
My script is:
INSERT INTO [Emp_table].[ACT].[LIST_EMP]
([ENTITY],[TYPE],[EMP_COD],[DATE],[LINE_NO],[ACT],[NAME])
VALUES
('REG','EMP','45233','2016-06-20 00:00:00:00','2','SKATING','JANE')
Will this do the trick?
Your statement looks ok. If the database has a problem with it (for example, due to a foreign key constraint violation), it will reject the statement.
If any of the fields in your table are numeric (and not varchar or char), just remove the quotes around the corresponding field. For example, if emp_cod and line_no are int, insert the following values instead:
('REG','EMP',45233,'2016-06-20 00:00:00:00',2,'SKATING','JANE')
Inserting records into a database has always been the most common reason why I've lost a lot of my hairs on my head!
SQL is great when it comes to SELECT or even UPDATEs but when it comes to INSERTs it's like someone from another planet came into the SQL standards commitee and managed to get their way of doing it implemented into the final SQL standard!
If your table does not have an automatic primary key that automatically gets generated on every insert, then you have to code it yourself to manage avoiding duplicates.
Start by writing a normal SELECT to see if the record(s) you're going to add don't already exist. But as Robert implied, your table may not have a primary key because it looks like a LOG table to me. So insert away!
If it does require to have a unique record everytime, then I strongly suggest you create a primary key for the table, either an auto generated one or a combination of your existing columns.
Assuming the first five combined columns make a unique key, this select will determine if your data you're inserting does not already exist...
SELECT COUNT(*) AS FoundRec FROM [Emp_table].[ACT].[LIST_EMP]
WHERE [ENTITY] = wsEntity AND [TYPE] = wsType AND [EMP_COD] = wsEmpCod AND [DATE] = wsDate AND [LINE_NO] = wsLineno
The wsXXX declarations, you will have to replace them with direct values or have them DECLAREd earlier in your script.
If you ran this alone and recieved a value of 1 or more, then the data exists already in your table, at least those 5 first columns. A true duplicate test will require you to test EVERY column in your table, but it should give you an idea.
In the INSERT, to do it all as one statement, you can do this ...
INSERT INTO [Emp_table].[ACT].[LIST_EMP]
([ENTITY],[TYPE],[EMP_COD],[DATE],[LINE_NO],[ACT],[NAME])
VALUES
('REG','EMP','45233','2016-06-20 00:00:00:00','2','SKATING','JANE')
WHERE (SELECT COUNT(*) AS FoundRec FROM [Emp_table].[ACT].[LIST_EMP]
WHERE [ENTITY] = wsEntity AND [TYPE] = wsType AND
[EMP_COD] = wsEmpCod AND [DATE] = wsDate AND
[LINE_NO] = wsLineno) = 0
Just replace the wsXXX variables with the values you want to insert.
I hope that made sense.

Create table with checksum of all tables in a database?

I'm trying to figure out how to determine if a table has been affected by a number of processes that run in sequence, and need to know what the state of the table is before and after each runs. What I've been trying to do is run some SQL before all the processes run that saves a before checksum of every table in the db to a table, then running it again when each ends and updating the table row with an after checksum. After all the processes are over, I compare the checksums and get all rows where before <> after.
Only problem is that I'm not the best guy for SQL, and am a little lost. Here's where I'm at right now:
select checksum_agg(binary_checksum(*)) from empcomp with (nolock)
create table Test_CheckSum_Record ( TableName varchar(max), CheckSum_Before int, CheckSum_After int)
SELECT name into #TempNames
FROM sys.Tables where is_ms_shipped = 0
And the pseudocode for what I want to do is something like
foreach(var name in #TempNames)
insert into Test_CheckSum_Record(name, ExecuteSQL N'select checksum_agg(binary_checksum(*)) from ' + name + ' with (nolock)', null)
But how does one do this?
Judging by the comments you need to create a trigger that handles all CRUD operations and just places a flag
Syntax is
Create TRIGGER [TriggerName] ON [TableName]
AFTER UPDATE, AFTER Delete, AFTER UPDATE
In the trigger you can do a
select CHECKSUM_AGG([Columns you want to compare against])
from [ParentTable] store that value in a variable and check it against the checksum table before column. If it does not exist you add a new entry with the DELETED tables checksum_AGG value as the before entry
Please note the choice not to use the inserted table is just preference for me on calculated columns
I will edit later when I have more time to add code

Rename table via sp_rename or ALTER SCHEMA

I am going to perform a table-wide update on a huge table (+200Millon records) so I am going to populate the data via SELECT into a separate table, than drop the original and rename the new one.
In one of the articles someone mentioned that it is better to create the new table with the same name in a temporary schema (e.g. 'clone') and switch it to the used one (e.g. 'dbo'), than to use the original schema with a temporary name and call sp_rename after the data is in place and the old table is dropped.
I was looking into this, but I cannot think of anything why the schema switch is better than the sp_rename. Can anyone find any good reason why is better to use the first or the second approach?
Thanks!
EDIT: I want to update the values in a specific column
EDIT2: Ultimately my question is, if I decide to go down the way of creating a new table to transfer data to which alternative to use:
CREATE TABLE dbo.newTable
...
DROP TABLE dbo.originalTable
EXEC sp_rename N'dbo.newTable', N'dbo.originalTable'
OR
CREATE TABLE clone.originalTable
...
DROP TABLE dbo.originalTable
ALTER SCHEMA dbo TRANSFER clone.originalTable
By the way, I would suggest that you WON'T populate the table by using SELECT * INTO. This will lock your source table for everyone else during the insertion, which could take quite a time.
Just a suggestion, try this instead:
SELECT TOP 0 INTO [newTable]
FROM [oldTable]
INSERT INTO [newTable]
SELECT * FROM [oldTable]
By the way, you can use sp_rename to rename your table to another name. But it won't change the schema. If you try to change the schema too it will produce a buggy table name.
You can instead try to move the table to another name. Example below:
EXEC sp_rename N'oldTable', N'oldTable_Backup'
EXEC sp_rename N'newTable', N'oldTable'
Hopefully this will help you.
Based on your edited answer the quickest way to do that is:
If you have to include default value to the column
ALTER TABLE {TABLENAME}
ADD {COLUMNNAME} {TYPE} {NULL|NOT NULL}
CONSTRAINT {CONSTRAINT_NAME} DEFAULT {DEFAULT_VALUE}
[WITH VALUES]
and then drop the old column from the table.
ALTER TABLE {TABLENAME} DROP COLUMN {OLD COLUMN}
If you have to update table column based calculated values
Disable index on the column which you are updating
Create index on the column which are in WHERE clause
Update statistics
Use WITH(NOLOCK) table hint [if you are fine with dirty read]
Update
As per edit 2, your first statement is about changing table name and second statement is about changing schema. They both are different and does not related to moving data or updating value. In this case, changing schema would be the best bet
If locking was an issue before it still is regardless of what version SQL Server that you are using. When you drop and rename you are also losing all the rights on the table.

How to change column order in a table using sql query in sql server 2005?

How to change column order in a table using SQL query in SQL Server 2005?
I want to rearrange column order in a table using SQL query.
You cannot. The column order is just a "cosmetic" thing we humans care about - to SQL Server, it's almost always absolutely irrelevant.
What SQL Server Management Studio does in the background when you change column order there is recreating the table from scratch with a new CREATE TABLE command, copying over the data from the old table, and then dropping it.
There is no SQL command to define the column ordering.
You have to explicitly list the fields in the order you want them to be returned instead of using * for the 'default' order.
original query:
select * from foobar
returns
foo bar
--- ---
1 2
now write
select bar, foo from foobar
bar foo
--- ---
2 1
according to https://learn.microsoft.com/en-us/sql/relational-databases/tables/change-column-order-in-a-table
This task is not supported using Transact-SQL statements.
Well, it can be done, using create/ copy / drop/ rename, as answered by komma8.komma1
Or you can use SQL Server Management Studio
In Object Explorer, right-click the table with columns you want to reorder and click Design (Modify in ver. 2005 SP1 or earlier)
Select the box to the left of the column name that you want to reorder. (You can select multiple columns by holding the [shift] or
the [ctrl] keys on your keyboard.)
Drag the column(s) to another location within the table.
Then click save. This method actually drops and recreates the table, so some errors might occur.
If Change Tracking option is enabled for the database and the table, you shouldn't use this method.
If it is disabled, the Prevent saving changes that require the table re-creation option should be cleared in Tools menu > Options > Designers, otherwise "Saving changes is not permitted" error will occur.
Disabling the Prevent saving changes that require the table re-creation option is strongly advised against by Microsoft, as it leads to the existing change tracking information being deleted when the table is re-created, so you should never disable this option if Change Tracking is enabled!
Problems may also arise during primary and foreign key creation.
If any of the above errors occurs, saving fails which leaves you with the original column order.
In SQLServer Management Studio:
Tools -> Options -> Designers -> Table and Database Designers
Unselect 'Prevent saving changes that require table re-creation'.
Then:
right click the table you want to re-order the columns for.
click 'Design'.
Drag the columns to the order you want.
finally, click save.
SQLServer Management studio will drop the table and recreate it using the data.
This is similar to the question on ordering the records in the result of a query .. and typically no one likes the formally correct answer ;-)
So here it goes:
as per SQL standard, the columns in a table are not "ordered"
as a result, a select * does not force the columns to be returned in a particular order
typically, each RDBMS has a kind of "default" order (usually the order that the columns were added to the table, either in the create table' or in thealter table add ` statements
therefore, if you rely on the order of columns (because you are using the results of a query to poulate some other datastructure from the position of the columns), explicitly list the columns in the order you want them.
You can of course change the order of the columns in a sql statement. However if you want to abstract tables' physical column order, you can create a view. i.e
CREATE TABLE myTable(
a int NULL,
b varchar(50) NULL,
c datetime NULL
);
CREATE VIEW vw_myTable
AS
SELECT c, a, b
FROM myTable;
select * from myTable;
a b c
- - -
select * from vw_myTable
c a b
- - -
You can do it by creating a new table, copy all the data over, drop the old table, then renaming the new one to replace the old one.
You could also add new columns to the table, copy the column by column data over, drop the old columns, then rename new columns to match the old ones. A simple example below:
http://sqlfiddle.com/#!3/67af4/1
CREATE TABLE TestTable (
Column1 INT,
Column2 VARCHAR(255)
);
GO
insert into TestTable values(1, 'Test1');
insert into TestTable values(2, 'Test2');
GO
select * from TestTable;
GO
ALTER TABLE TestTable ADD Column2_NEW VARCHAR(255);
ALTER TABLE TestTable ADD Column1_NEW INT;
GO
update TestTable
set Column1_NEW = Column1,
Column2_NEW = Column2;
GO
ALTER TABLE TestTable DROP COLUMN Column1;
ALTER TABLE TestTable DROP COLUMN Column2;
GO
sp_rename 'TestTable.Column1_NEW', 'Column1', 'COLUMN';
GO
sp_rename 'TestTable.Column2_NEW', 'Column2', 'COLUMN';
GO
select * from TestTable;
GO
In SQLServer Management Studio:
Tools -> Options -> Designers -> Table and Database Designers
Unselect Prevent saving changes that require table re-creation.
Now you can reorder the table.
Sql server internally build the script. It create a temporary table with new changes and copy the data and drop current table then recreate the table insert from temp table. I find it from "Generate Change script" option ssms 2014. Script like this. From Here: How to change column order in a table using sql query
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_emps
(
id int NULL,
ename varchar(20) NULL
) ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_emps SET (LOCK_ESCALATION = TABLE)
GO
IF EXISTS(SELECT * FROM dbo.emps)
EXEC('INSERT INTO dbo.Tmp_emps (id, ename)
SELECT id, ename FROM dbo.emps WITH (HOLDLOCK TABLOCKX)')
GO
DROP TABLE dbo.emps
GO
EXECUTE sp_rename N'dbo.Tmp_emps', N'emps', 'OBJECT'
GO
COMMIT
If your table has enough columns then you can try this. First create a new table with preferred order of columns.
create table new as select column1,column2,column3,....columnN from table_name;
Now drop the table using drop command
drop table table_name;
now rename the newly created table to your old table name.
rename new to table_name;
now select the table, you have your columns rearranged as you preferred before.
select * from table_name;
Not sure if still relevant, but SSMS can generate a change scripts for this.
Re-order (drag the column) the table in Designer View
Click on 'Generate Change Script'
The generated script contains the script which does the following:
Create a temporary table
Adds the constraints, relationships and triggers from original table to temporary table
Drop original table
Rename temporary table to original table name
If you have not yet added any data into your table yet, there is one way to move the columns around.
Try this:
In SSMS, click Tools > Options > Designers > Table and Database Designers > Uncheck the box next to Prevent saving changes that require table re-creation > Click OK.
In the object tree, right-click on your table and select Design > in the thin column to the left of the Column Name column, you can click and drag the columns around to wherever you want them. When you're done, just go to close the Design tab and SSMS will ask you if you want to save your changes, click OK.
Optional:
3. Re-enable the checkbox for the option from Step 1 to re-secure your table.
Hope this helps someone!
Credit goes to Microsoft:
https://learn.microsoft.com/en-us/troubleshoot/sql/ssms/error-when-you-save-table#more-information
At the end of the day, you simply cannot do this in MS SQL. I recently created tables on the go (application startup) using a stored Procedure that reads from a lookup table. When I created a view that combined these with another table I had manually created earlier one (same schema, with data), It failed - simply because I was using ''Select * UNION Select * ' for the view. At the same time, if I use only those created through the stored procedure, I am successful.
In conclusion: If there is any application which depends on the order of column it is really not good programming and will for sure create problems in the future. Columns should 'feel' free to be anywhere and be used for any data process (INSERT, UPDATE, SELECT).
You can achieve it with these steps:
remove all foreign keys and primary key of the original table.
rename the original table.
using CTAS create the original table in the order you want.
drop the old table.
apply all constraints back to the original table
If the columns to be reordered have recently been created and are empty, then the columns can be deleted and re-added in the correct order.
This happened to me, extending a database manually to add new functionality, and I had missed a column out, and when I added it, the sequence was incorrect.
After finding no adequate solution here I simply corrected the table using the following kind of commands.
ALTER TABLE tablename DROP COLUMN columnname;
ALTER TABLE tablename ADD columnname columntype;
Note: only do this if you don't have data in the columns you are dropping.
People have said that column order does not matter. I regularly use SQL Server Management Studio "generate scripts" to create a text version of a database's schema. To effectively version control these scripts (git) and to compare them (WinMerge), it is imperative that the output from compatible databases is the same, and the differences highlighted are genuine database differences.
Column order does matter; but just to some people, not to everyone!
Use
SELECT * FROM TABLE1
which displays the default column order of the table.
If you want to change the order of the columns.
Specify the column name to display correspondingly
SELECT COLUMN1, COLUMN5, COLUMN4, COLUMN3, COULMN2 FROM TABLE1
you can use indexing.. After indexing, if select * from XXXX results should be as per the index, But only result set.. not structrue of Table
In order to have a specific column order You need to select column by column in the order You wish.
Selection order dictates how columns will be ordered in output.
Try this command:
alter table students modify age int(5) first;
This will change the position of age to the first position.
You can change this using SQL query. Here is sql query to change the sequence of column.
ALTER TABLE table name
CHANGE COLUMN `column1` `column1` INT(11) NOT NULL COMMENT '' AFTER `column2`;
alter table name modify columnname int(5) first;
will bring the column to first
alter table name modify columnname int(5) after (tablename);
This worked for me on Oracle DB:
select column1, column2, t.* from table t
Example: Change position of field_priority after field_price in table status.
ALTER TABLE `status` CHANGE `priority` `priority` INT(11) NULL DEFAULT NULL AFTER `price`;

Is there an easy way to add a custom migration script to SQL Compare scripts?

At my work we are currently having some serious pains pushing our database changes across environments. The issue starts to show up when we create a new non-nullable column on an existing table. The script that SQL Compare generates creates the column as non-nullable, so it will always fail. I was hoping that there was some alternative to having to manually edit the script. Is there any way to get around this? If not, how do you guys handle it?
Create a table:
create table #bingo ( id int )
Add a value:
insert into #bingo values (1)
Add a new column:
alter table #bingo add userid int
Populate the new column:
update #bingo set userid = 1 where id = 1
Change the new column to not nullable:
alter table #bingo alter column userid int not null
You would have to manually edit the RedGate Sql Compare to make it work like this.
How do you plan on filling the NOT NULL column? I don't see how SQL Compare could really come up with a solution since it has no way of knowing how you would fill it.
You could create the column with a DEFAULT, then simply add an update statement at the end of the generated scripts to properly update the column if you have some source for the values.
add a default onto the new not null column
when creating a new not null column, what value do all the existing rows get? If you don't know, make the column nullable.