INFORMATION_SCHEMA.columns won't list two columns - sql

I have the following code which is supposed to display the column name, data type, size, # of filled columns and the total rows.
The problem that I am running into is that using INFORMATION_SCHEMA.columns I can only display either DATA_TYPE or CHARACTER_MAXIMUM_LENGTH. If I try to SELECT both I get errors:
An expression of non-boolean type specified in a context where a condition is expected, near 'si'.
The code statement is:
DECLARE #TableName VARCHAR(512) = 'state';
DECLARE #SQL VARCHAR(1024);
WITH SQLText AS (
SELECT
ROW_NUMBER() OVER (ORDER BY c.Name) AS RowNum,
'SELECT ''' + c.name + ''',
MAX(b.DATA_TYPE) AS ''Data Type'',
SUM(CASE WHEN ' + c.Name + ' IS NULL THEN 0 ELSE 1 END) AS ''Filled Values'',
COUNT(*) AS ''Total Records''
FROM INFORMATION_SCHEMA.columns b
JOIN ' + #TableName + ' ON b.column_name = ''' + c.name +'''' AS SQLRow
FROM
sys.tables t
INNER JOIN sys.columns c ON c.object_id = t.object_id
JOIN sys.types a ON c.user_type_id = a.user_type_id
WHERE
t.name = #TableName)
Any ideas on how to get both to display?

DECLARE #TableName VARCHAR(512) = 'Settings';
DECLARE #SQL VARCHAR(1024);
WITH SQLText AS (
SELECT
ROW_NUMBER() OVER (ORDER BY c.Name) AS RowNum,
'SELECT ''' + c.name + ''',
MAX(b.DATA_TYPE) AS ''Data Type'',
Max(b.CHARACTER_MAXIMUM_LENGTH) as ''CHARACTER_MAXIMUM_LENGTH'',
SUM(CASE WHEN ' + c.Name + ' IS NULL THEN 0 ELSE 1 END) AS ''Filled Values'',
COUNT(*) AS ''Total Records''
FROM INFORMATION_SCHEMA.columns b
JOIN ' + #TableName + ' ON b.column_name = ''' + c.name +'''' AS SQLRow
FROM
sys.tables t
INNER JOIN sys.columns c ON c.object_id = t.object_id
JOIN sys.types a ON c.user_type_id = a.user_type_id
WHERE
t.name = #TableName)
select * from SQLText
This works for me, tbh though i'd add to get a better idea of the size a column uses.
SUM(CASE WHEN ' + c.Name + ' IS NULL THEN 0 ELSE Datalength(' + c.Name + ') END) AS ''Filled Values'',

Related

Pass table name as parameter

I want to pass the table name as parameter and get all columns size of that table altered by column length + 50.
alter PROCEDURE dbo.testsp
#tablename varchar(100)
AS
BEGIN
DECLARE
#totalWeight TABLE (columnnames nvarchar(100));
INSERT INTO #totalWeight (columnnames)
SELECT name FROM sys.columns
WHERE object_id = object_id(#tablename);
END
GO
This query returns your alteration statements in the last column. You can then run them through dynamic sql.
SELECT
tbl.name 'Table Name',
c.name 'Column Name',
t.name,
c.max_length 'Max Length in Bytes',
c.precision ,
c.scale ,
c.is_nullable,
q1.*,
'alter table ['
+tbl.name
+'] alter column ['
+c.name
+'] '
+t.name
+'('+
convert(nvarchar(1000), CASE WHEN t.name IN ('nchar','nvarchar') THEN c.max_length/2 ELSE c.max_length END +50)
+') '
+ case c.is_nullable when 0 then ' not null' else ' null' end
as 'Alteration statement'
FROM
sys.columns c
INNER JOIN
sys.types t ON c.user_type_id = t.user_type_id
inner join sys.tables tbl on tbl.object_id=c.object_id
CROSS APPLY
(
select
t.name +
CASE WHEN t.name IN ('char', 'varchar','nchar','nvarchar') THEN '('+
CASE WHEN c.max_length=-1 THEN 'MAX'
ELSE CONVERT(VARCHAR(4),
CASE WHEN t.name IN ('nchar','nvarchar')
THEN c.max_length/2 ELSE c.max_length END )
END +')'
WHEN t.name IN ('decimal','numeric')
THEN '('+ CONVERT(VARCHAR(4),c.precision)+','
+ CONVERT(VARCHAR(4),c.Scale)+')'
ELSE '' END
+ case c.is_nullable when 0 then ' not null' else ' null' end
as [DDL name before]
)q1
where t.name IN ('char', 'varchar','nchar','nvarchar') and c.max_length>-1
Run the following example of query, it creates a bunch of ALTER statements. Copy-paste the result into a new query window and run it again. Add other data types from sys.types if need.
SELECT 'ALTER TABLE [' + s.name + '].[' + t.name + '] ALTER COLUMN [' +
c.name + '] ' + ty.name + '(' + CAST(c.max_length + 50 AS nvarchar(10)) + ') ' +
CASE WHEN c.is_nullable = 1 THEN 'NULL' ELSE 'NOT NULL' END + ';'
FROM sys.tables t
INNER JOIN sys.columns c ON t.object_id = c.object_id
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
INNER JOIN sys.types ty ON c.system_type_id = ty.system_type_id
WHERE t.type = 'U' AND
c.system_type_id IN (167 /*varchar*/, 231 /*nvarchar*/)

SQL query optimization

I am trying to find out a script that can help me in Data Density of my DBs. the point is I already figure out the query and what I do need but the problem is the query takes for ever. it works find for small DBs, but that doesn't happen a lot.
So I am looking for kind of optimization or any ideas to help me.
the script:
DECLARE Cur CURSOR
FOR
SELECT DB_Name() AS DatabaseName
,s.[name] AS SchemaName
,t.[name] AS TableName
,c.[name] AS ColumnName
,'[' + DB_Name() + ']' + '.[' + s.NAME + '].' + '[' + T.NAME + ']' AS FullQualifiedTableName
,d.[name] AS DataType
FROM sys.schemas s
INNER JOIN sys.tables t ON s.schema_id = t.schema_id
INNER JOIN sys.columns c ON t.object_id = c.object_id
INNER JOIN sys.types d ON c.user_type_id = d.user_type_id
WHERE d.NAME LIKE '%int%'
OR d.NAME LIKE '%float%'
OR d.NAME LIKE '%decimal%'
OR d.NAME LIKE '%numeric%'
OR d.NAME LIKE '%real%'
OR d.NAME LIKE '%money%'
OR d.NAME LIKE '%date%'
OR d.NAME LIKE '%datetime%'
AND is_identity = 0
OPEN Cur
FETCH NEXT
FROM Cur
INTO #DatabaseName
,#SchemaName
,#TableName
,#ColumnName
,#FullyQualifiedTableName
,#DataType
WHILE ##FETCH_STATUS = 0 -- The FETCH statement was successful.
BEGIN
DECLARE #SQL VARCHAR(MAX) = NULL
SET #SQL = ' Select ''' + #DatabaseName + ''' AS DatabaseName, ''' +
#SchemaName + ''' AS TableName,
''' + #TableName + ''' AS SchemaName,
''' + #ColumnName + ''' AS ColumnName,
''' + #DataType + ''' AS ColumnName,
(Select MAX(' + #ColumnName + ') from ' + #FullyQualifiedTableName + ' with (nolock))
AS MaxValue,
(Select MIN(' + #ColumnName + ') from ' + #FullyQualifiedTableName + ' with (nolock))
AS MinValue,
(Select COUNT(*) from ' + #FullyQualifiedTableName + ' with (nolock))
AS CountValue,
(Select COUNT(*) from ' + #FullyQualifiedTableName + ' Where ' + #ColumnName + ' IS NOT NULL )
AS NotNULLCount,
(Select 0 from ' + #FullyQualifiedTableName + ')
AS DataDensity'
PRINT #SQL
The following script will give me the MAX, MIN, COUNT, NotNULLCount and the DATA DENSITY for every and each column form the declared types above. but u can imagine a DB with 70 tables and each table has 30-50 columns....
running this script will take for ever.
You should always try and avoid using cursors, this query will give you a list of select queries that you can copy and paste to get the data that you require. Note also I have removed the sub selects as they are not required:
SELECT 'Select ''' + DB_Name() + ''' AS DatabaseName, ''' + s.Name + ''' AS SchemaName, ''' + t.Name + ''' AS TableName, ''' + c.Name + ''' AS ColumnName, ''' + d.Name + ''' AS ColumnName,' +
'MAX([' + c.Name + ']) AS MaxValue,' +
'MIN([' + c.Name + ']) AS MinValue,' +
'COUNT(*) AS CountValue,' +
'COUNT([' + c.Name + ']) AS NotNullCount,' +
'CAST(COUNT(DISTINCT [' + c.name + ']) AS float) / COUNT([' + C.Name + ']) AS DataDensity ' +
'from [' + DB_Name() + '].[' + s.Name + '].[' + t.name + '] with (nolock)'
FROM sys.schemas s
INNER JOIN sys.tables t ON s.schema_id = t.schema_id
INNER JOIN sys.columns c ON t.object_id = c.object_id
INNER JOIN sys.types d ON c.user_type_id = d.user_type_id
WHERE d.NAME LIKE '%int%'
OR d.NAME LIKE '%float%'
OR d.NAME LIKE '%decimal%'
OR d.NAME LIKE '%numeric%'
OR d.NAME LIKE '%real%'
OR d.NAME LIKE '%money%'
OR d.NAME LIKE '%date%'
OR d.NAME LIKE '%datetime%'
AND is_identity = 0
This will give you a list of select statements in the following form:
Select 'MyDB' AS DatabaseName, 'dbo' AS SchemaName, 'MyTable' AS TableName, 'ID' AS ColumnName, 'int' AS ColumnName,MAX([ID]) AS MaxValue,MIN([ID]) AS MinValue,COUNT(*) AS CountValue,COUNT([ID]) AS NotNullCount,CAST(COUNT(DISTINCT [ID]) AS float) / COUNT([ID]) AS DataDensity from [MyDB].[dbo].[MyTable] with (nolock)
Of course SQL Server stores these sorts of statistics for useful columns, You can find which ones it has be using:
EXEC SP_HELPSTATS 'MyTable', 'ALL'
Then using the list of statistics returned such as:
_WA_Sys_00000014_004FB3FB ID
to get the actual stats using:
DBCC SHOW_STATISTICS('MyTable','_WA_Sys_00000002_004FB3FB')
This will return data like:
Name Updated Rows Rows Sampled Steps Density Average key length String Index Filter Expression Unfiltered Rows
_WA_Sys_00000002_004FB3FB Jan 8 2017 8:01PM 16535 16535 200 0.2493151 4.459389 NO NULL 16535
and
All density Average Length Columns
0.0006038647 4.459389 EffectiveDate
and another rowset showing a histogram of values.
You can automatically generate these DBCC commands using:
SELECT 'DBCC SHOW_STATISTICS([' + OBJECT_NAME(s.object_Id) + '],''' + s.Name + ''')'
FROM sys.stats s
INNER JOIN sys.stats_columns sc
ON s.object_id = sc.object_id AND s.stats_id = sc.stats_id
INNER JOIN sys.columns c
ON sc.object_id = c.object_id AND sc.column_id = c.column_id
WHERE s.Name LIKE '_WA%'
ORDER BY s.stats_id, sc.column_id;

SQL get table columns with type name

I have successfully getting the information of tables and columns from below query.
Is there any handy way to get the type name with the description like nvarchar(20), numeric(14,2), varchar(max) etc. instead of lot's of CASE statements?
SELECT
o.name AS TableName,
c.name AS ColumnName,
t.name +
CASE
WHEN t.name LIKE '%char' THEN '(' +
CASE
WHEN c.max_length = -1 THEN 'max'
ELSE CONVERT(varchar(10), c.max_length / CASE WHEN t.name LIKE 'n%' THEN 2 ELSE 1 END)
END + ')'
WHEN t.name IN ('numeric', 'decimal') THEN '(' + CONVERT(varchar(4), c.precision) + ',' + CONVERT(varchar(4), c.scale) + ')'
-- WHEN .... many other types
ELSE ''
END AS TypeName
FROM
sys.objects o
INNER JOIN sys.columns c ON o.object_id = c.object_id
INNER JOIN sys.types t ON t.system_type_id = c.system_type_id AND t.user_type_id = c.user_type_id
WHERE
o.is_ms_shipped = 0
ORDER BY
o.name,
c.column_id
Edit
sp_help nor the information schema return the name not being like nvarchar(20), numeric(14,2), varchar(max)
I use this view to Document the Database.... you could used this and use the data_type and Length/Precision
/****** Object: View [dbo].[vw_DataDictionary] Script Date: 17/07/2015 10:24:04 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER VIEW [dbo].[vw_DataDictionary]
AS
SELECT TOP (100) PERCENT tb.name AS Table_Name, CAST(ept.value AS nvarchar(200)) AS Table_Description, CAST(c.name AS nvarchar(200)) AS Column_Name,
CAST(ep.value AS nvarchar(200)) AS column_Description, t.name AS data_type, c.is_nullable AS Is_Null, object_definition(c.default_object_id) AS default_text,
c.max_length AS Length, c.precision AS numeric_precision, c.scale AS numeric_scale, c.column_id
FROM sys.columns AS c LEFT OUTER JOIN
sys.tables AS tb ON tb.object_id = c.object_id LEFT OUTER JOIN
sys.types AS t ON c.system_type_id = t.system_type_id AND c.user_type_id = t.user_type_id LEFT OUTER JOIN
sys.extended_properties AS ept ON ept.major_id = tb.object_id AND ept.minor_id = 0 AND ept.name = 'MS_Description' LEFT OUTER JOIN
sys.extended_properties AS ep ON ep.major_id = c.object_id AND ep.minor_id = c.column_id AND ep.name = 'MS_Description'
WHERE (tb.type = 'U') AND (tb.name <> 'sysdiagrams')
ORDER BY Table_Name, c.column_id
GO
For SQL Server 2008 R2, I have declared the type by CASE as below:
SQL Fiddle
SELECT
DB_NAME() AS DatabaseName,
SCHEMA_NAME(o.schema_id) AS SchemaName,
o.name AS ObjectName,
c.name AS ColumnName,
RTRIM(o.type) AS ObjectType,
t.name AS TypeName,
c.max_length AS Length,
-- The logic is implemented in this column
t.name +
CASE
-- (max) for char type / binary only
WHEN (t.name LIKE '%char%' OR t.name LIKE '%binary') AND c.max_length = -1 THEN '(max)'
-- (n) where n = length / 2 for nchar and nvarchar
WHEN t.name LIKE '%char%' AND LEFT(t.name, 1) = 'n' THEN '(' + CONVERT(varchar, c.max_length / 2) + ')'
-- (n) where n = length
WHEN t.name LIKE '%char%' OR t.name LIKE '%binary' THEN '(' + CONVERT(varchar, c.max_length) + ')'
-- (p,s) where p = precision, s = scale
WHEN t.name IN ('numeric', 'decimal') THEN '(' + CONVERT(varchar, c.precision) + ',' + CONVERT(varchar, c.scale) + ')'
-- (s) where s = scale
WHEN t.name IN ('time', 'datetime2', 'datetimeoffset') THEN '(' + CONVERT(varchar, c.scale) + ')'
ELSE ''
END AS Type
FROM
sys.objects o
inner join sys.columns c on o.object_id = c.object_id
inner join sys.types t on c.system_type_id = t.system_type_id and c.user_type_id = t.user_type_id
WHERE 1 = 1
AND o.is_ms_shipped = 1
This should help you, Adopted from here
DECLARE #tblname VARCHAR(300)
SET #tblname = 'tblname'
SELECT o.list AS ColumnsDescription
FROM sysobjects so
CROSS APPLY (
SELECT ' [' + column_name + '] ' + data_type + CASE data_type
WHEN 'sql_variant'
THEN ''
WHEN 'text'
THEN ''
WHEN 'ntext'
THEN ''
WHEN 'xml'
THEN ''
WHEN 'decimal'
THEN '(' + cast(numeric_precision AS VARCHAR) + ', ' + cast(numeric_scale AS VARCHAR) + ')'
ELSE coalesce('(' + CASE
WHEN character_maximum_length = - 1
THEN 'MAX'
ELSE cast(character_maximum_length AS VARCHAR)
END + ')', '')
END + ' ' + CASE
WHEN EXISTS (
SELECT id
FROM syscolumns
WHERE object_name(id) = so.NAME
AND NAME = column_name
AND columnproperty(id, NAME, 'IsIdentity') = 1
)
THEN 'IDENTITY(' + cast(ident_seed(so.NAME) AS VARCHAR) + ',' + cast(ident_incr(so.NAME) AS VARCHAR) + ')'
ELSE ''
END + ' ' + (
CASE
WHEN IS_NULLABLE = 'No'
THEN 'NOT '
ELSE ''
END
) + 'NULL ' + CASE
WHEN information_schema.columns.COLUMN_DEFAULT IS NOT NULL
THEN 'DEFAULT ' + information_schema.columns.COLUMN_DEFAULT
ELSE ''
END + ', '
FROM information_schema.columns
WHERE table_name = so.NAME
ORDER BY ordinal_position
FOR XML PATH('')
) o(list)
LEFT JOIN information_schema.table_constraints tc ON tc.Table_name = so.NAME
AND tc.Constraint_Type = 'PRIMARY KEY'
CROSS APPLY (
SELECT '[' + Column_Name + '], '
FROM information_schema.key_column_usage kcu
WHERE kcu.Constraint_Name = tc.Constraint_Name
ORDER BY ORDINAL_POSITION
FOR XML PATH('')
) j(list)
WHERE xtype = 'U'
AND NAME = #tblname
You can parse your results as you want.
SELECT
COLUMN_NAME,
CASE
WHEN DATA_TYPE ='decimal' THEN DATA_TYPE+ '('+cast (NUMERIC_PRECISION as Varchar)+ ','+cast (NUMERIC_SCALE as Varchar)+ ')'
WHEN CHARACTER_MAXIMUM_LENGTH is null THEN DATA_TYPE + cast ('' as Varchar)
ELSE DATA_TYPE + '('+ cast (CHARACTER_MAXIMUM_LENGTH as Varchar)+')' END AS QuantityText
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = 'table_name' and TABLE_SCHEMA = 'dbo'
order by COLUMN_NAME

find all columns and tables in a database which contain a particular case sensitive string

I would like to find all the tables in my database where the columns "Column1" & "Column2" contain a specific case sensitive string 'aBcD'.Is there a way to do it ?
I came up with the following query . Any suggestions ?
SELECT c.name AS ColName, t.name AS TableName
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
WHERE c.name = 'Column1' or c.name = 'Column2' and
/* column contents is 'aBcD' */ ?
One solution could be to iterate over all found tables and check their content like this:
DECLARE cur CURSOR FOR
SELECT t.name, c.name
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
WHERE c.name = 'Column1' or c.name = 'Column2'
OPEN cur
CREATE TABLE #output(tablename nvarchar(255), columnname nvarchar(255))
DECLARE #sql nvarchar(max), #tab nvarchar(max), #col nvarchar(max)
FETCH NEXT FROM cur INTO #tab, #col
WHILE(##FETCH_STATUS = 0) BEGIN
SET #sql = N'
IF(SELECT COUNT(*)
FROM '+#tab+'
WHERE '+#col+' = N''aBcD''
COLLATE Latin1_General_CS_AS) > 0
INSERT INTO #output(tablename, columname)
VALUES(N'''+#tab+''',N'''+#col+''')'
EXEC(#sql)
FETCH NEXT FROM cur INTO #tab, #col
END
SELECT * FROM #output
-- Cleanup
CLOSE cur
DEALLOCATE cur
DROP TABLE #output
My buddy Chris Morris at sqlservercentral.com posted this a few years ago. I modified it slightly to be a little more flexible. This will generate a series of select statements which is much faster than using a cursor. If you wanted to you could shove the results of this into a variable and execute it. Or you can just copy and paste several of these into another query window and run them.
DECLARE #MySearchCriteria VARCHAR(500)
SET #MySearchCriteria = '''This user registration has been rejected''' --you do need all these quotation marks because this string is injected to another string.
SELECT 'SELECT ' + c.columnlist + '] FROM [' + t.name + '] WHERE ' + w.whereclause + ';' as SelectStatement
FROM sys.tables t
CROSS APPLY (
SELECT STUFF((
SELECT '], [' + c.Name AS [text()]
FROM sys.columns c
join sys.types t2 on t2.user_type_id = c.user_type_id
WHERE t.object_id = c.object_id
AND c.collation_name IS NOT NULL
AND c.max_length > 6
and t2.name not in ('text', 'ntext')
FOR XML PATH('')
), 1, 2, '' )
) c (columnlist)
CROSS APPLY (
SELECT STUFF((
SELECT ' OR [' + c.Name + '] IN (' + #MySearchCriteria + ')' AS [text()]
FROM sys.columns c
join sys.types t2 on t2.user_type_id = c.user_type_id
WHERE t.object_id = c.object_id
AND c.collation_name IS NOT NULL
AND c.max_length > 6
and t2.name not in ('text', 'ntext')
FOR XML PATH('')
), 1, 4, '' )
) w (whereclause)
where c.columnlist is not null
ORDER BY t.name

Easiest Way To Diff Two Table Schemas In SQL Server 2008?

I have to do checks between a development and release database and do this manually, which is both slow and not 100% reliable (I only visually inspect the tables).
Is there a quick and easy way to compare table schemas automatically? Maybe even a feature that does this built right into SQL server?
Edit: I'm comparing structure only, thank you for pointing this out.
I'm a fan of SQL DBDiff, which is an open source tool you can use to compare tables, views, functions, users, etc. of two instances of SQL Server databases and generate a change script between the source and destination databases.
There are some commercial products that do this; Visual Studio 2010 Premium Edition can compare schemas.
Some others:
http://www.red-gate.com/products/SQL_Compare/index.htm
http://www.apexsql.com/sql_tools_diff.aspx
Data or structure or both? Try RedGate sql compare or data compare. They both have free trials and are awesome.
http://www.red-gate.com/products/SQL_Compare/index.htm
http://www.red-gate.com/products/SQL_Data_Compare/index.htm
I'm a little late to the game...but this script I made has worked well for me. It'll work across linked servers too if needed.
use master
go
DECLARE #Server1 VARCHAR(100) ='[CARNYSQLTEST1].'; --include a dot at the end
DECLARE #DB1 VARCHAR(100) = '[ZipCrim]';
DECLARE #Table1 VARCHAR(100) = 'IntAction';
DECLARE #Server2 VARCHAR(100) ='[CARNYSQLDEV].'; --include a dot at the end
DECLARE #DB2 VARCHAR(100) = '[ZipCrim]';
DECLARE #Table2 VARCHAR(100) = 'IntAction';
DECLARE #SQL NVARCHAR(MAX);
SET #SQL =
'
SELECT Table1.ServerName,
Table1.DBName,
Table1.SchemaName,
Table1.TableName,
Table1.ColumnName,
Table1.name DataType,
Table1.Length,
Table1.Precision,
Table1.Scale,
Table1.Is_Identity,
Table1.Is_Nullable,
Table2.ServerName,
Table2.DBName,
Table2.SchemaName,
Table2.TableName,
Table2.ColumnName,
Table2.name DataType,
Table2.Length,
Table2.Precision,
Table2.Scale,
Table2.Is_Identity,
Table2.Is_Nullable
FROM
(SELECT ''' + #Server1 + ''' ServerName,
''' + #DB1 + ''' DbName,
SCHEMA_NAME(t.schema_id) SchemaName,
t.Name TableName,
c.Name ColumnName,
st.Name,
c.Max_Length Length,
c.Precision,
c.Scale,
c.Is_Identity,
c.Is_Nullable
FROM ' + #Server1 + #DB1 + '.sys.tables t
INNER JOIN ' + #Server1 + #DB1 + '.sys.columns c ON t.Object_ID = c.Object_ID
INNER JOIN sys.types st ON St.system_type_id = c.System_Type_id AND st.user_type_id = c.user_type_id
WHERE t.Name = ''' + #Table1 + ''') Table1
FULL OUTER JOIN
(SELECT ''' + #Server2 + ''' ServerName,
''' + #DB2 + ''' DbName,
SCHEMA_NAME(t.schema_id) SchemaName,
t.name TableName,
c.name ColumnName,
st.Name,
c.max_length Length,
c.Precision,
c.Scale,
c.Is_Identity,
c.Is_Nullable
FROM ' + #Server2 + #DB2 + '.sys.tables t
INNER JOIN ' + #Server2 + #DB2 + '.sys.columns c ON t.Object_ID = c.Object_ID
INNER JOIN sys.types st ON St.system_type_id = c.System_Type_id AND st.user_type_id = c.user_type_id
WHERE t.Name = ''' + #Table2 + ''') Table2
ON Table1.ColumnName = Table2.ColumnName
ORDER BY CASE WHEN Table1.ColumnName IS NULL THEN 2 ELSE 1 END, Table1.ColumnName
'
EXEC sp_executesql #SQL
Soo,
Googled this:
for structures:
see also:
My previous answers' links doesn't work anymore for some reason, so here's another answer from TechNet:
DECLARE #Sourcedb sysname
DECLARE #Destdb sysname
DECLARE #Tablename sysname
DECLARE #SQL varchar(max)
SELECT #Sourcedb = '<<SourceDatabaseName>>'
SELECT #Destdb = '<<DestinationDatabaseName>>'
SELECT #Tablename = '<<Tablename>>' -- '%' for all tables
SELECT #SQL = ' SELECT Tablename = ISNULL(Source.tablename,Destination.tablename)
,ColumnName = ISNULL(Source.Columnname,Destination.Columnname)
,Source.Datatype
,Source.Length
,Source.precision
,Destination.Datatype
,Destination.Length
,Destination.precision
,[Column] =
Case
When Source.Columnname IS NULL then ''Column Missing in the Source''
When Destination.Columnname IS NULL then ''Column Missing in the Destination''
ELSE ''''
end
,DataType = CASE WHEN Source.Columnname IS NOT NULL
AND Destination.Columnname IS NOT NULL
AND Source.Datatype <> Destination.Datatype THEN ''Data Type mismatch''
END
,Length = CASE WHEN Source.Columnname IS NOT NULL
AND Destination.Columnname IS NOT NULL
AND Source.Length <> Destination.Length THEN ''Length mismatch''
END
,Precision = CASE WHEN Source.Columnname IS NOT NULL
AND Destination.Columnname IS NOT NULL
AND Source.precision <> Destination.precision THEN ''precision mismatch''
END
,Collation = CASE WHEN Source.Columnname IS NOT NULL
AND Destination.Columnname IS NOT NULL
AND ISNULL(Source.collation_name,'''') <> ISNULL(Destination.collation_name,'''') THEN ''Collation mismatch''
END
FROM
(
SELECT Tablename = so.name
, Columnname = sc.name
, DataType = St.name
, Length = Sc.max_length
, precision = Sc.precision
, collation_name = Sc.collation_name
FROM ' + #Sourcedb + '.SYS.objects So
JOIN ' + #Sourcedb + '.SYS.columns Sc
ON So.object_id = Sc.object_id
JOIN ' + #Sourcedb + '.SYS.types St
ON Sc.system_type_id = St.system_type_id
AND Sc.user_type_id = St.user_type_id
WHERE SO.TYPE =''U''
AND SO.Name like ''' + #Tablename + '''
) Source
FULL OUTER JOIN
(
SELECT Tablename = so.name
, Columnname = sc.name
, DataType = St.name
, Length = Sc.max_length
, precision = Sc.precision
, collation_name = Sc.collation_name
FROM ' + #Destdb + '.SYS.objects So
JOIN ' + #Destdb + '.SYS.columns Sc
ON So.object_id = Sc.object_id
JOIN ' + #Destdb + '.SYS.types St
ON Sc.system_type_id = St.system_type_id
AND Sc.user_type_id = St.user_type_id
WHERE SO.TYPE =''U''
AND SO.Name like ''' + #Tablename + '''
) Destination
ON source.tablename = Destination.Tablename
AND source.Columnname = Destination.Columnname '
EXEC (#Sql)
For a free solution, you can use SQL Server Managements Objects to output the DDL script for each table, view, index, SP, UDF, etc. Then you can compare, either in code, or using a diff tool like WinMerge.
If two tables in same database, you can use this query
select c2.table_name,c2.COLUMN_NAME
from [INFORMATION_SCHEMA].[COLUMNS] c2
where table_name='table1'
and c2.COLUMN_NAME not in (select column_name
from [INFORMATION_SCHEMA].[COLUMNS]
where table_name='table1')
you can take a look at http://cdttools.com/2011/10/sql-diff-erence/ its a low cost alternative, will walk schema between two databases and tell you whats changed. You can then use SQL Mgmt studio to generate "script->As Alter" to build change scripts. (caveat: I wrote it)
Modified a bit of BD.'s query, all credit goes to him. (Changed SCHEMA_NAME(schema_id) to sys.schemas join because SCHEMA_NAME(schema_id) works with current db context which is master, changed sorting and changed column names and added the status column)
USE master
GO
DECLARE
#Server1 VARCHAR(100) = 'Server1.', -- don't forget to include a dot at the end
#Server2 VARCHAR(100) = 'Server2.', -- don't forget to include a dot at the end
#DB1 VARCHAR(100) = 'Database1',
#DB2 VARCHAR(100) = 'Database2'
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = '
SELECT
CASE
WHEN s1.[Column] IS NOT NULL
AND s2.[Column] IS NULL
THEN ''New''
WHEN s1.[Column] IS NULL
AND s2.[Column] IS NOT NULL
THEN ''Deleted''
WHEN s1.[Column] IS NOT NULL
AND s2.[Column] IS NOT NULL
AND (s1.[Type] <> s2.[Type]
OR s1.[Length] <> s2.[Length]
OR s1.[Precision] <> s2.[Precision]
OR s1.Scale <> s2.Scale
OR s1.IsNullable <> s2.IsNullable
OR s1.IsIdentity <> s2.IsIdentity
OR s1.IdentitySeed <> s2.IdentitySeed
OR s1.IdentityIncrement <> s2.IdentityIncrement
OR s1.DefaultValue <> s2.DefaultValue)
THEN ''Changed''
ELSE ''Identical''
END [Status],
s1.[Database],
s1.[Schema],
s1.[Table],
s1.[Column],
s1.[Type],
s1.IsCharType,
s1.[Length],
s1.[Precision],
s1.Scale,
s1.IsNullable,
s1.IsIdentity,
s1.IdentitySeed,
s1.IdentityIncrement,
s1.DefaultValue,
s1.[Order],
s2.[Database],
s2.[Schema],
s2.[Table],
s2.[Column],
s2.[Type],
s2.IsCharType,
s2.[Length],
s2.[Precision],
s2.Scale,
s2.IsNullable,
s2.IsIdentity,
s2.IdentitySeed,
s2.IdentityIncrement,
s2.DefaultValue,
s2.[Order]
FROM (
SELECT
''' + #DB1 + ''' AS [Database],
s.name AS [Schema],
t.name AS [Table],
c.name AS [Column],
tp.name AS [Type],
CASE
WHEN tp.collation_name IS NOT NULL
THEN 1
ELSE 0
END AS IsCharType,
CASE
WHEN c.max_length = -1
THEN ''MAX''
ELSE CAST(c.max_length AS VARCHAR(4))
END AS [Length],
c.[precision],
c.scale,
c.is_nullable AS IsNullable,
c.is_identity AS IsIdentity,
CAST(ISNULL(ic.seed_value, 0) AS INT) AS IdentitySeed,
CAST(ISNULL(ic.increment_value, 0) AS INT) AS IdentityIncrement,
dc.definition AS DefaultValue,
c.column_id AS [Order]
FROM ' + #Server1 + #DB1 + '.sys.tables t
INNER JOIN ' + #Server1 + #DB1 + '.sys.schemas s ON s.schema_id = t.schema_id
INNER JOIN ' + #Server1 + #DB1 + '.sys.columns c ON c.object_id = t.object_id
INNER JOIN ' + #Server1 + #DB1 + '.sys.types tp ON tp.system_type_id = c.system_type_id
LEFT OUTER JOIN ' + #Server1 + #DB1 + '.sys.identity_columns ic ON ic.object_id = t.object_id AND ic.name = c.name
LEFT OUTER JOIN ' + #Server1 + #DB1 + '.sys.default_constraints dc ON dc.object_id = c.default_object_id
) s1
FULL OUTER JOIN (
SELECT
''' + #DB2 + ''' AS [Database],
s.name AS [Schema],
t.name AS [Table],
c.name AS [Column],
tp.name AS [Type],
CASE
WHEN tp.collation_name IS NOT NULL
THEN 1
ELSE 0
END AS IsCharType,
CASE
WHEN c.max_length = -1
THEN ''MAX''
ELSE CAST(c.max_length AS VARCHAR(4))
END AS [Length],
c.[precision],
c.scale,
c.is_nullable AS IsNullable,
c.is_identity AS IsIdentity,
CAST(ISNULL(ic.seed_value, 0) AS INT) AS IdentitySeed,
CAST(ISNULL(ic.increment_value, 0) AS INT) AS IdentityIncrement,
dc.definition AS DefaultValue,
c.column_id AS [Order]
FROM ' + #Server2 + #DB2 + '.sys.tables t
INNER JOIN ' + #Server2 + #DB2 + '.sys.schemas s ON s.schema_id = t.schema_id
INNER JOIN ' + #Server2 + #DB2 + '.sys.columns c ON c.object_id = t.object_id
INNER JOIN ' + #Server2 + #DB2 + '.sys.types tp ON tp.system_type_id = c.system_type_id
LEFT OUTER JOIN ' + #Server2 + #DB2 + '.sys.identity_columns ic ON ic.object_id = t.object_id AND ic.name = c.name
LEFT OUTER JOIN ' + #Server2 + #DB2 + '.sys.default_constraints dc ON dc.object_id = c.default_object_id
) s2
ON s2.[Schema] = s1.[Schema]
AND s2.[Table] = s1.[Table]
AND s2.[Column] = s1.[Column]
ORDER BY
CASE WHEN s1.[Database] IS NULL THEN s2.[Database] ELSE s1.[Database] END,
CASE WHEN s1.[Schema] IS NULL THEN s2.[Schema] ELSE s1.[Schema] END,
CASE WHEN s1.[Table] IS NULL THEN s2.[Table] ELSE s1.[Table] END,
CASE WHEN s1.[Order] IS NULL THEN s2.[Order] ELSE s1.[Order] END
'
EXEC sp_executesql #SQL
You can use the SQL Management studio tools to "Generate scripts" from both databases. Then use your favorite text comparison tool to see any differences.
In the old days, this worked great, but in SQL 2005 the generate script code changed and the objects were no longer created in the same order, so the text comparison is less useful. I have not tested this in more recent versions of SQL so it may have been fixed. You can also try http://exportsqlscript.codeplex.com/ which I have used with good success to output the DDL as scripts for source code control and comparing versions.
References:
https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=332400&wa=wsignin1.0
http://social.msdn.microsoft.com/Forums/en-US/sqltools/thread/505fd238-e0dc-42ae-8a54-2dceace81bb3/
http://exportsqlscript.codeplex.com/