Compare tables columns(types,collation,nullable...) and update 2nd one according to found differences - sql-server

I have two Dbs on the same server named 'DB_prod' and 'DB_test', and they are simply the same.
I need to assume that someone can modify table on 'DB_prod'. The script need to find all columns differences (types,collation,nullable,max length) + find new columns, and alter it to table on the 'DB_test'.
There are no relationships between tables.
First step is to find diffrences and I know how to accomplish this.
The secound step would be to move all chages to 'DB_test'.
The only idea I have for now is to use dynamic sql, so write diffrent table 'alters' and execute them in cursor.
Any other idea?
All work need to be done by procedure(s).
Thanks

A database-scoped trigger is probably what you're looking for. You can use it to record the alter table statements to a table TriggerLog and then run your stored procedure to execute the statements on your test table.
--Table to hold your event data.
CREATE TABLE TriggerLog
(
Event_Data NVARCHAR(MAX),
Username NVARCHAR(250),
Event_Date DATETIME
)
CREATE TRIGGER trg_alter_table ON DATABASE --database level trigger
FOR ALTER_TABLE
AS
INSERT TriggerLog
SELECT EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)'),
COALESCE(SUSER_SNAME(),USER_NAME()),
GETDATE();
GO
ALTER TABLE ProdTable
ADD column1 VARCHAR(100);
SELECT *
FROM triggerlog
Results:
Event_data Username Event_Date
------------------------------------------------------------------------------------------
ALTER TABLE ProdTable ADD column1 VARCHAR(100); Domain\User 2015-03-16 09:29:47.387

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.

insert only certain columns of a stored procedure into a temptable in one step

I have a storedprocedure which has multiple columns. I want to insert only certain columns of this stored procedure into a temp table.
CREATE TABLE #Temp
(
Product VARCHAR(MAX),
)
INSERT INTO #Temp (Product)
EXEC mpaGetProducts
Currently I get the error :
"Column name or number of supplied values does not match table definition"
I do not want to insert into one table first and then select only required columns because there is a large amount of data and this would cause a hit on the performance.
I saw this post & a few others online but it wasn't very helpful :
Insert results of a stored procedure into a temporary table
What you want is not possible. There is no way to specify the columns you want to select directly from a stored procedure.
EDIT: Actually, a slightly hacky way to do this is with OPENQUERY:
SELECT {Columns that I want}
FROM OPENQUERY(MyServer, 'EXEC MyStoredProc #Params');
Please Provide SP Description
If you run your SP the output might have several columns resulting in SELECT STATEMENT so try to mention what column you need to insert into table

How does SQL Server Database Project: Publish decide when to recreate a table?

I have a SQL Server Database Project in which I've made several changes to the schema where I've changed column data types from NUMERIC (18,0) to INT. We're trying to normalize the data type used for Primary Keys, it's a currently 50/50 mix.
When I generate the Publish script, some of the tables are recreated in the script:
CREATE TABLE [dbo].[tmp_XYZ]
INSERT TABLE [dbo].[tmp_XYZ] SELECT ... FROM [dbo].[XYZ]
DROP TABLE [dbo].[XYZ]
sp_rename N'[dbo].[tmp_XYZ]', N'XYZ';
but other tables are just updated via ALTER statements
ALTER TABLE [dbo].[ABC] ALTER COLUMN [AbcID] INT NULL;
Is there some rule that dictates when a table will be recreated, and when it's just altered in place ?
Probably the best way is to Right Click on your object name and choose script as ...
Then you have options to create or alter
If you couldn't find Alter ,you can go to design view, right click and choose Generate Change Script ... to find the alter statement.
This is just an easy problem. It's the same problem as changing a table in the table designer. I think you've changed a column inside your table design which needs to drop and recreate the table to let the column order in the same position.
Here is a short example. Take this table design as given:
CREATE TABLE dbo.Test(
id int identity(1,1),
firstname nvarchar(100),
name nvarchar(100),
street nvarchar(100)
)
This will create the columns in a specified order. You can see this order here:
SELECT name, column_id
FROM sys.columns
WHERE object_id = OBJECT_ID(N'dbo.Test')
You'll see something like that:
column_name column_id
id 1
firstname 2
name 3
street 4
If you change the the column name via designer or in your case in the data project, this will cause SQL Server to obtain this order upright.
In this case you try to change the column name to lastname. This will enforce SQL Management Studio and other programs like that to keep the column_id upright. This can only be done, if the table is completely recreated with the right columnorder. SQL Server create a temporary table stub, insert everything into it, drop the old table and rename the temporary table to the old original name. Just as in your code above.
After that you'll see something like that:
column_name column_id
id 1
firstname 2
lastname 3
street 4
If you would simply rename the last column or do it manually, everything would be fine. Manually would be much more efficient, as there isn't the need to move ALL data to a new table. The manual way would be this:
-- Create the new column
ALTER TABLE dbo.Test ADD lastname nvarchar(100)
GO
-- Populate the new column using the old one
UPDATE dbo.Test
SET lastname = name
GO
-- Drop the old column afterwards
ALTER TABLE dbo.Test DROP COLUMN name
This behavior will result in the following result:
column_name column_id
id 1
firstname 2
street 4
lastname 5
The last one will be much more efficient, as already stated.
Hopefully this will answer your question, even if the answer comes lately.

SQL Server : alter table type

What happens when you execute the same alter column several times, e.g:
ALTER table1 ALTER column column1 varchar(40)
ALTER table1 ALTER column column1 varchar(40)
...
Does SQL Server compare altering types in first place or does it use the same mechanism for every alter?
You can check the transaction log, or use table change tracking, or use CDC to track, then you will find out what id the difference between first time and second time. You will see no difference.

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`;

Resources