Compare columns data types and size in same database in SQL Server - sql-server-2012

I need a query that could help me to compare column datatype and column size between two tables in same database.
For example I have these sample tables in the same database:
Table Names
-----------
I_A
I_B
I_C
T_A
T_B
T_C
ABC
I have to compare columns data types or columns size is mismatched between I AND T tables.
For example, I have to compare I_A with T_A table and I_B with T_B table like this.

I believe a query like this will identify column differences. If you also need to identify columns that exist on one table but not the other, use a FULL OUTER JOIN in the final SELECT tweak the WHERE clause to include rows with a NULL in either I or T values.
WITH
i_tables AS (
SELECT
RIGHT(t.name, 1) AS table_suffix
, c.name AS column_name
, ty.name AS type_name
, c.max_length
, c.precision
, c.scale
, c.is_nullable
FROM sys.tables AS t
JOIN sys.columns AS c ON
c.object_id = t.object_id
JOIN sys.types AS ty ON
ty.system_type_id = c.system_type_id
AND ty.user_type_id = c.user_type_id
WHERE t.name LIKE 'I[_]_'
)
,t_tables AS (
SELECT
RIGHT(t.name, 1) AS table_suffix
, c.name AS column_name
, ty.name AS type_name
, c.max_length
, c.precision
, c.scale
, c.is_nullable
FROM sys.tables AS t
JOIN sys.columns AS c ON
c.object_id = t.object_id
JOIN sys.types AS ty ON
ty.system_type_id = c.system_type_id
AND ty.user_type_id = c.user_type_id
WHERE t.name LIKE 'T[_]_'
)
SELECT *
FROM i_tables
JOIN t_tables ON
t_tables.table_suffix = i_tables.table_suffix
AND t_tables.column_name = i_tables.column_name
WHERE
t_tables.type_name <> i_tables.type_name
AND t_tables.max_length <> i_tables.max_length
AND t_tables.precision <> i_tables.precision
AND t_tables.scale <> i_tables.scale
AND t_tables.is_nullable <> i_tables.is_nullable;

Related

Get SQL Server's constraints list without redundancy

With this query I get the list of all my database's CHECK, FOREIGN_KEY, PRIMARY_KEY and UNIQUE_KEY constraints.
SELECT
o.object_id as ID, o.name AS Name,
OBJECT_NAME(o.parent_object_id) AS TableName,
o.type_desc AS TypeName,
cs.COLUMN_NAME as ColumnName
FROM
sys.objects o
LEFT JOIN
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cs ON o.name = cs.CONSTRAINT_NAME
WHERE
o.type = 'C' or o.type = 'F' or o.type = 'PK' or o.type = 'UQ'
However, there are some of them with many 'ColumnName' and I want to concat this.
For example :
'PK_ENTITE_SIGN_DOSSIER_ID_DOSSIER_ID_ENTITE_ID_GROUPE_SIGN_ID_PERSONNE_ID_SCHEMA'
is a PRIMARY_KEY on table ENTITE_SIGN_DOSSIER and contains ID_DOSSIER, ID_ENTITE, ID_GROUPE_SIGN, ID_PERSONNE and ID_SCHEMA (5 columns) and in this case, my query return 5 lines for this constraint.
How can I concat those columns name on the query's result please ?
Thanks a lot for your help
This is standard xml and stuff function trick:
SELECT o.object_id AS ID ,
o.name AS Name ,
OBJECT_NAME(o.parent_object_id) AS TableName ,
o.type_desc AS TypeName ,
ca.ColumnName
FROM sys.objects o
CROSS APPLY ( SELECT STUFF(( SELECT ', ' + cs.COLUMN_NAME
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cs
WHERE o.name = cs.CONSTRAINT_NAME
FOR
XML PATH('')
), 1, 2, '') AS ColumnName
) ca
WHERE o.type = 'C'
OR o.type = 'F'
OR o.type = 'PK'
OR o.type = 'UQ'
ORDER BY ID

SQL Search for a Binary value

I've seen similar queries where a string or character value is used to search an entire database. Those queries do not return results that lie in a BINARY(8) field. I've tried to modify those queries to no avail.
Is there a way to search the entire database for specific binary values, such as 0x0000000000000017?
Thanks guys.
You can use the system tables to find this.
MSSQL:
SELECT t.name AS table_name,
c.name AS column_name,
ty.name
FROM sys.tables AS t
INNER JOIN sys.columns c
ON t.OBJECT_ID = c.OBJECT_ID
INNER JOIN sys.types ty
ON t.schema_id = ty.schema_id
WHERE ty.system_type_id = 173
ORACLE:
SELECT owner,table_name, column_name,data_TYPE
FROM all_tab_columns where data_TYPE = 'RAW';
Well...
select *
from foo
where foo.binary8column = 0x0000000000000017
should do. If you want to enumerate all the tables and find all the binary or varbinary columns, this query
select table_name = object_schema_name(tn.object_id) + '.' + tn.name ,
column_name = c.name ,
type = t.name + '(' + convert(varchar,c.max_length) + ')'
from sys.types t
join sys.columns c on c.system_type_id = t.system_type_id
join sys.tables tn on tn.object_id = c.object_id
where t.name in ( 'binary', 'varbinary' )
and c.max_length >= 8
should give enough information to generate the queries for every such table.

determining where column collations don't match

I'm getting the below collation conflict error when I try to join two fairly large tables via a UNION ALL statement.
SELECT * FROM [TABLEA]
UNION ALL
SELECT * FROM [TABLEB]
Msg 457, Level 16, State 1, Line 1
Implicit conversion of varchar value to varchar cannot be performed because the collation of the value is unresolved due to a collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "SQL_Latin1_General_CP1_CS_AS" in UNION ALL operator.
I would like to identify which columns exactly are mismatched but am unfamiliar with querying sys.columns or information_schema.
This should do (assuming that the columns on both tables have the same names):
SELECT *
FROM ( SELECT *
FROM sys.columns
WHERE OBJECT_NAME(object_id) = 'TABLEA') A
INNER JOIN (SELECT *
FROM sys.columns
WHERE OBJECT_NAME(object_id) = 'TABLEB') B
ON A.name = B.name
WHERE A.collation_name <> B.collation_name
Just replace MyTable1 and MyTable2 with your tables names
SELECT OBJECT_NAME(c.object_id) as TableName
,c.name AS ColumnName
,c.collation_name as CollationName
FROM sys.columns AS c
JOIN sys.tables AS t
ON c.object_id = t.object_id
WHERE t.name IN ( 'MyTableA', 'MyTableB' )
AND c.collation_name IS NOT NULL
In case column names are exactly the same than you can do this
WITH TableA
AS (
SELECT OBJECT_NAME(c.object_id) AS TableName
,c.name AS ColumnName
,c.collation_name AS CollationName
FROM sys.columns AS c
JOIN sys.tables AS t
ON c.object_id = t.object_id
WHERE t.name IN ( 'TableA' )
AND c.collation_name IS NOT NULL
),
TableB
AS (
SELECT OBJECT_NAME(c.object_id) AS TableName
,c.name AS ColumnName
,c.collation_name AS CollationName
FROM sys.columns AS c
JOIN sys.tables AS t
ON c.object_id = t.object_id
WHERE t.name IN ( 'TableB' )
AND c.collation_name IS NOT NULL
)
SELECT a.TableName
,a.ColumnName
,a.CollationName
,b.TableName
,b.ColumnName
,b.CollationName
FROM tableA AS a
JOIN TableB AS b
ON a.ColumnName = b.ColumnName
AND a.CollationName <> b.CollationName
OK everyone's using sys.columns... I'll use information_schema just in case he's on SQL 2000 ;)
If column names are the same (and in same order):
SELECT *
FROM (SELECT TABLE_NAME, COLUMN_NAME, COLLATION_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='TABLEA') A,
(SELECT TABLE_NAME, COLUMN_NAME, COLLATION_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='TABLEB') B
WHERE A.COLUMN_NAME = B.COLUMN_NAME
AND ISNULL(A.COLLATION_NAME,'') <> ISNULL(B.COLLATION_NAME,'')
Or, to compare by column order (ordinal):
SELECT *
FROM (SELECT TABLE_NAME, COLUMN_NAME, COLLATION_NAME, ORDINAL_POSITION
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='TableA') A
FULL OUTER JOIN (SELECT TABLE_NAME, COLUMN_NAME, COLLATION_NAME, ORDINAL_POSITION
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='TableB') B
ON A.ORDINAL_POSITION = B.ORDINAL_POSITION
WHERE ISNULL(A.COLLATION_NAME,'') <> ISNULL(B.COLLATION_NAME,'')
This should get you started in that direction.
WITH CTE as
( SELECT tbl.NAME AS Table_name
, col.NAME AS [Column_name]
, col.collation_name
, col.column_id
FROM sys.columns col
INNER JOIN sys.tables tbl
ON col.object_id = tbl.object_id
WHERE Col.collation_name in ('SQL_Latin1_General_CP1_CI_AS'
,'SQL_Latin1_General_CP1_CS_AS')
)
SELECT * FROM CTE A
inner join CTE b
on A.column_id=B.column_id
WHERE A.Table_name='PSS601'
and B.Table_name='PSS604'
and A.collation_name <> B.collation_name
Then to change the collation use the COLLATE keyword.
Column_name COLLATE Collation_name

How to find which indexes and constraints contain a specific column?

I am planing a database change and I have a list of columns included in process. Can I list all indexes in which is a specific column included?
Edit
So far I have (combined from answers):
declare #TableName nvarchar(128), #FieldName nvarchar(128)
select #TableName= N'<<Table Name>>', #FieldName =N'<<Field Name>>'
(SELECT distinct systab.name AS TABLE_NAME,sysind.name AS INDEX_NAME, 'index'
FROM sys.indexes sysind
INNER JOIN sys.index_columns sysind_col
ON sysind.object_id = sysind_col.object_id and sysind.index_id = sysind_col.index_id
INNER JOIN sys.columns sys_col
ON sysind_col.object_id = sys_col.object_id and sysind_col.column_id = sys_col.column_id
INNER JOIN sys.tables systab
ON sysind.object_id = systab.object_id
WHERE systab.is_ms_shipped = 0 and sysind.is_primary_key=0 and sys_col.name =#FieldName and systab.name=#TableName
union
select t.name TABLE_NAME,o.name, 'Default' OBJ_TYPE
from sys.objects o
inner join sys.columns c on o.object_id = c.default_object_id
inner join sys.objects t on c.object_id = t.object_id
where o.type in ('D') and c.name =#FieldName and t.name=#TableName
union
SELECT u.TABLE_NAME,u.CONSTRAINT_NAME, 'Constraint' OBJ_TYPE
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE u
where u.COLUMN_NAME = #FieldName and u.TABLE_NAME = #TableName
) order by 1
But I am not too happy with combining of sys. and 'INFORMATION_SCHEMA.' Can it be avoided?
---Using sp_helpindex and your TableName
exec sp_helpindex YourTableName
---Using sys.tables with your TableName and ColumnName
select distinct c.name, i.name, i.type_desc,...
from sys.indexes i
join sys.index_columns ic on i.index_id = ic.index_id
join sys.columns c on ic.column_id = c.column_id
where i.object_id = OBJECT_ID(N'YourTableName') and c.name = 'YourColumnName'
EDIT: As per comment, you can also join object_Ids without using distinct
select c.name, i.name, i.type_desc
from sys.indexes i
join sys.index_columns ic on i.index_id = ic.index_id and i.object_id = ic.object_id
join sys.columns c on ic.column_id = c.column_id and ic.object_id = c.object_id
where i.object_id = OBJECT_ID(N'YourTableName') and c.name = 'YourColumnName'
SELECT * FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE
USE TABLE_NAME IN WHERE if you what to know the constraint on a table.
and use column_name if you know the column name.
To get information regarding all indexes in which is a specific column is included following two catalog views can be used:
sys.indexes , sys.index_columns
Query:
SELECT
sysind.name AS INDEX_NAME
,sysind.index_id AS INDEX_ID
,sys_col.name AS COLUMN_NAME
,systab.name AS TABLE_NAME
FROM sys.indexes sysind
INNER JOIN sys.index_columns sysind_col
ON sysind.object_id = sysind_col.object_id and sysind.index_id = sysind_col.index_id
INNER JOIN sys.columns sys_col
ON sysind_col.object_id = sys_col.object_id and sysind_col.column_id = sys_col.column_id
INNER JOIN sys.tables systab
ON sysind.object_id = systab.object_id
WHERE (1=1)
AND systab.is_ms_shipped = 0
AND sys_col.name IN(specific column list for which indexes are to be queried)
ORDER BY
systab.name,sys_col.name, sysind.name,sysind.index_id
Hope this helps!
If you have access to the sys schema on your database then you can query sys.indexes to get the index ID and use that with the function index_col to get the columns. The final parameter for index_col is the index of the column within the index (i.e. if there are 3 columns in the index you would have to call index_col 3 times with 1, 2, 3 in the last parameter)
select index_id from sys.indexes
where object_id = object_id(#objectname)
select index_col(#objectname, #indexid, 1)
This should give you constraints as well as they are just special indexes.

SQL Server search for a column by name

I'm doing some recon work and having to dig through a few hundred SQL Server database tables to find columns.
Is there a way to easily search for columns in the database and return just the table name that the column belongs to?
I found this, but that also returns Stored procedures with that column name in it...
SELECT OBJECT_NAME(object_id) FROM sys.columns WHERE name = 'foo'
This includes views though but can be further filtered . It may be useful though.
More generally...
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = 'foo'
sys.columns
To get the
1) full column name
2) object name (including schema)
3) object type (table/view)
4) data type (nice format: varchar(6) or numeric(5,2), etc.)
5) null/not null
6) information on identity, check constraint, and default info
try this:
DECLARE #Search varchar(200)
SET #Search='YourColumnName' --can be a partial or a complete name
SELECT
s.name as ColumnName
,sh.name+'.'+o.name AS ObjectName
,o.type_desc AS ObjectType
,CASE
WHEN t.name IN ('char','varchar') THEN t.name+'('+CASE WHEN s.max_length<0 then 'MAX' ELSE CONVERT(varchar(10),s.max_length) END+')'
WHEN t.name IN ('nvarchar','nchar') THEN t.name+'('+CASE WHEN s.max_length<0 then 'MAX' ELSE CONVERT(varchar(10),s.max_length/2) END+')'
WHEN t.name IN ('numeric') THEN t.name+'('+CONVERT(varchar(10),s.precision)+','+CONVERT(varchar(10),s.scale)+')'
ELSE t.name
END AS DataType
,CASE
WHEN s.is_nullable=1 THEN 'NULL'
ELSE 'NOT NULL'
END AS Nullable
,CASE
WHEN ic.column_id IS NULL THEN ''
ELSE ' identity('+ISNULL(CONVERT(varchar(10),ic.seed_value),'')+','+ISNULL(CONVERT(varchar(10),ic.increment_value),'')+')='+ISNULL(CONVERT(varchar(10),ic.last_value),'null')
END
+CASE
WHEN sc.column_id IS NULL THEN ''
ELSE ' computed('+ISNULL(sc.definition,'')+')'
END
+CASE
WHEN cc.object_id IS NULL THEN ''
ELSE ' check('+ISNULL(cc.definition,'')+')'
END
AS MiscInfo
FROM sys.columns s
INNER JOIN sys.types t ON s.system_type_id=t.system_type_id and t.is_user_defined=0
INNER JOIN sys.objects o ON s.object_id=o.object_id
INNER JOIN sys.schemas sh on o.schema_id=sh.schema_id
LEFT OUTER JOIN sys.identity_columns ic ON s.object_id=ic.object_id AND s.column_id=ic.column_id
LEFT OUTER JOIN sys.computed_columns sc ON s.object_id=sc.object_id AND s.column_id=sc.column_id
LEFT OUTER JOIN sys.check_constraints cc ON s.object_id=cc.parent_object_id AND s.column_id=cc.parent_column_id
WHERE s.name LIKE '%'+#Search+'%'
select c.name as ColumnName, o.name as TableName
from sys.columns c
inner join sys.objects o on c.object_id = o.object_id
where c.name = 'MyColumnName'
http://www.red-gate.com/products/SQL_Search/index.htm?utm_source=google&utm_medium=cpc&utm_content=brand_aware&utm_campaign=sqlsearch&gclid=COSfqe_mmKQCFSE1gwodSxOrEQ
This should do it for you. I use it everyday.
This stored procedure will search for table.name and column.name pairs.
I use when I have "WhateverId" in code and I want to know where that is (probably) stored in the database without actually having to read through and understand the code. :)
CREATE OR ALTER PROC FindColumns
#ColumnName VARCHAR(MAX) = NULL,
#TableName VARCHAR(MAX) = NULL
AS
SELECT T.[name] AS TableName, C.[name] AS ColumnName
FROM sys.all_columns C
JOIN sys.tables T ON C.object_id = T.object_id
JOIN sys.types CT ON C.user_type_id = CT.user_type_id
WHERE (#ColumnName IS NULL OR C.[name] LIKE '%' + TRIM(#ColumnName) + '%')
AND (#TableName IS NULL OR T.[name] LIKE '%' + TRIM(#TableName) + '%')
ORDER BY T.[name], C.[name]
select table_name from information_schema.columns
where column_name = '<your column name here>'
Using the information_schema views is 'more correct' as system details in the system databases are subject to change between implementations of SQL Server.