Find Identity columns from another database - sql-server

Normally with SQL Server you can use the COLUMNPROPERTY function like this to find the Identity columns in a database:
select TABLE_NAME + '.' + COLUMN_NAME, TABLE_NAME
from INFORMATION_SCHEMA.COLUMNS
where TABLE_SCHEMA = 'dbo'
and COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1
order by TABLE_NAME
But I can't figure out how to get this to work when running the query from another database. E.g. this does not return any results:
Use FirstDatabase
Go
select TABLE_NAME + '.' + COLUMN_NAME, TABLE_NAME
from SecondDatabase.INFORMATION_SCHEMA.COLUMNS
where TABLE_SCHEMA = 'dbo'
and COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1
order by TABLE_NAME

Object_ID only works in current db, unless you use a 3-part name, but that form is complicated to use. Also, ColumnProperty only works in current db.
select o.name + '.' + c.name, o.name
from test1.sys.columns c
join test1.sys.objects o on c.object_id = o.object_id
join test1.sys.schemas s on s.schema_id = o.schema_id
where s.name = 'dbo'
and o.is_ms_shipped = 0 and o.type = 'U'
and c.is_identity = 1
order by o.name

There is no way to get information with the help of COLUMNPROPERTY from another database. But there is on workaround:
DECLARE #DatabaseName VARCHAR(MAX)
DECLARE #TableName VARCHAR(MAX)
DECLARE #SQL VARCHAR(MAX)
SET #DatabaseName = 'MyDatabase'
SET #TableName = 'MyTable'
SET #SQL = '
SELECT
C.TABLE_NAME,
C.COLUMN_NAME,
S.IS_IDENTITY
FROM ' + #DatabaseName + '.INFORMATION_SCHEMA.COLUMNS AS C
LEFT JOIN ' + #DatabaseName + '.SYS.COLUMNS AS S ON OBJECT_ID(''' + #DatabaseName + '.dbo.' + #TableName + ''') = S.OBJECT_ID AND C.COLUMN_NAME = S.NAME
WHERE S.IS_IDENTITY = 1'
EXEC(#SQL)

This worked for me using a specific database:
USE <database_name>;
GO
SELECT SCHEMA_NAME(schema_id) AS schema_name
, t.name AS table_name
, c.name AS column_name
FROM sys.tables AS t
JOIN sys.identity_columns c ON t.object_id = c.object_id
ORDER BY schema_name, table_name;
GO

In this example, I've constructed a stored procedure in "Database1" that uses dynamic SQL to retrieve column information from a table in "Database2" (using the [INFORMATION_SCHEMA].[COLUMNS] system view residing in "Database2"):
ALTER PROCEDURE [Database1].[Schema1].[ColumnNames] #Database2 nvarchar(128), #Schema2 nvarchar(128), #Table2 nvarchar(128)
AS
BEGIN
DECLARE #Sql nvarchar(1000)
SET #Sql = 'SELECT [COLUMN_NAME], [ORDINAL_POSITION] FROM [' + #Database2 + '].[INFORMATION_SCHEMA].[COLUMNS]
WHERE [TABLE_SCHEMA] = ''' + #Schema2 + ''' AND [TABLE_NAME] = ''' + #Table2 + ''''
EXEC(#Sql)
END

I'm using SQL Server 2019, and I have run into the same challenge. I'm not sure if this fix will work for older versions, but there is a view in each DB called Your-DB-Name.sys.identity_columns. If you select from this view, you'll see the list of identity columns you have defined in that DB.
From that information you should be able to write a join connecting YourDBName.Information_schema.columns such as below:
SELECT *
FROM YourDBName.Information_Schema.columns col
LEFT OUTER JOIN YourDBName.sys.identity_columns idc
ON idc.name = col.COLUMN_NAME AND idc.object_id = object_id('YourDBName..YourTableName')
WHERE col.TABLE_NAME = 'YourTableName' AND col.table_catalog = 'YourDBName';
The YourDbName.sys.identity_columns view contains the following fields that might be useful:
object_id (used to join back to the table in question in case you have multiple tables with the same identity field name)
name (the name of the Identity field)
column_id (the order of the column in your table)
is_identity (tells you if this is an identity field)
seed_value (the initial value of the identity field)
increment_value (how much the identity field goes up with each insert)

Related

SQL Server Query to get Data from a Table where each row is a Table

I have a schema where I have multiple tables some with time and some without it. So I created a query where I have listed 3 tables say which has time like this :
WITH CTE AS
(
SELECT
CONCAT(schema_name(t.schema_id), '.', t.name) AS table_name,
c.name AS 'time'
FROM
sys.tables t
INNER JOIN
sys.columns c ON c.object_id = t.object_id
WHERE
schema_name(t.schema_id) = 'Prod'
AND c.name = 'mytime'
)
SELECT * FROM CTE
Now my output looks like ( I am showing 3 rows for the example):
Table O
table_name time
--------------------------
Prod.tableA mytime
Prod.tableB mytime
Prod.tableC mytime
So usually what I want is to get the max(mytime) from each Table/Schema combination . So for a single table I can do
SELECT MAX(mytime)
FROM Prod.tableA
However in this case I want to generate this from table O for each table and my output should look like:
Table F
table_name mymax(time)
--------------------------------------------
Prod.tableA max(mytime) from Prod.tableA
Prod.tableB max(mytime) from Prod.tableA
Prod.tableC max(mytime) from Prod.tableA
How to achieve this using another select/variable declaration etc? Any help or ideas will be extremely appreciated. Thanks in anticipation.
Can this help? You still have a bit of work, check if the output is what you like and then uncomment the exec.
DECLARE #SchemaName NVARCHAR(100) = 'foo',
#ColumnName NVARCHAR(100) = 'bar',
#sql NVARCHAR(max)
SELECT #SchemaName + '.'+ t.name AS [Schema.Table],'( SELECT MAX(' + #ColumnName + ') FROM ['+ #SchemaName +'].['+t.name+']) ' AS MaxValue
FROM sys.tables t
JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE s.name = #SchemaName
-------
SELECT #sql =
STUFF((
SELECT 'UNION ALL ' + 'SELECT ' + '''' + '[' + ISNULL(#SchemaName,'') + '].['+ t.name + ']' + '''' + ' AS [Schema.Table] ,( SELECT MAX(' + #ColumnName + ') FROM ['+ #SchemaName +'].['+t.name+']) AS Max' + #ColumnName + ' '
FROM sys.tables t
JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE s.name = #SchemaName
for xml path('')
),1,10,'')
PRINT #sql
--EXEC(#sql)

How to get all the table names and distinct values in a particular column from a database for the tables which have a column using SQL Server

I am trying to get all the table names and the values present in a particular column if the column is present in the database. For the tables without the column ignore those.
For example: Find all the table name and values from a column 'last_refresh_date' in a database for all the tables with last_refresh_date column.
The code I tried is:
EXEC sp_MSforeachtable 'SELECT distinct ''?'' TableName, last_refresh_date FROM ?'
I get an error as some of the tables doesn't have the column name 'last_refresh_date' in it.
Thanks for the help in advance
I'm going to assume you are using a recent version of SQL Server, and thus have access to STRING_AGG, if not you'll need to use the "old" FOR XML PATH method.
Anyway, you achieve this with a little bit of dynamic SQL, and UNION ALL. I assume you want the table and schema names as well:
DECLARE #SQL nvarchar(MAX),
#ColumnName sysname = N'YourColumnName',
#CRLF nchar(2) = CHAR(13) + CHAR(10);
DECLARE #Delimiter nvarchar(30) = #CRLF + N'UNION ALL' + #CRLF
SET #SQL = (SELECT STRING_AGG(N'SELECT N' + QUOTENAME(s.[name],'''') + N' AS SchemaName, N' + QUOTENAME(t.[name],'''') + N' AS TableName, ' + QUOTENAME(c.[name]) + N' FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]), #Delimiter) WITHIN GROUP (ORDER BY t.object_id)
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
JOIN sys.columns c ON t.object_id = c.object_id
WHERE c.[name] = #ColumnName)
EXEC sys.sp_executesql #SQL;

SQL Server - find all tables in database with unique ID value

I want to find out all the tables in the database (in SQLServer) that has the column IDName with particular value 'SAM', like so IDName='SAM'. So my initial apporach was create a table with all the tables that have the column "IDName" (since not all the tables in the database has this column. Then i was thinking of going through each table to see which tables match the IDName='SAM' - This is where i'm stuck. I'm pretty sure there is a lot faster way of doing this too but im not too familiar with database query coding. Anything will help Thanks!
select * into tmp from
(
SELECT SO.NAME AS TableName, SC.NAME AS ColumnName
FROM dbo.sysobjects SO INNER JOIN dbo.syscolumns SC ON SO.id = SC.id
WHERE sc.name = 'IDName' and SO.type = 'U'
) tablelist
So if I go Select * from tmp, I get the list of tables that have the column "IDName". Now I have to go through each one of that list and see if they have "IDName = 'Sam'" if they do add it to the output table. In the end I want to see all the names of the tables from the database that has the IDName 'Sam'.
DECLARE #sql AS varchar(max) = '';
DECLARE #ColumnName AS varchar(100) = 'IDName'
DECLARE #ResultQuery AS varchar(max) = 'SELECT ''#TableName'' AS TableName ' +
' ,#ColumnName ' +
'FROM #TableName ' +
'WHERE #ColumnName = ''SAM''';
SET #ResultQuery = REPLACE(#ResultQuery, '#ColumnName', QUOTENAME(#ColumnName));
WITH AllTables AS (
SELECT SCHEMA_NAME(Tables.schema_id) AS SchemaName
,Tables.name AS TableName
,Columns.name AS ColumnName
FROM sys.tables AS Tables
INNER JOIN sys.columns AS Columns
ON Tables.object_id = Columns.object_id
WHERE Columns.name = #ColumnName
)
SELECT #sql = #sql + ' UNION ALL ' +
REPLACE(#ResultQuery, '#TableName', QUOTENAME(TableName)) + CHAR(13)
FROM AllTables
SET #sql = STUFF(#sql, 1, LEN(' UNION ALL'), '');
--PRINT #sql;
SET #sql =
'WITH AllTables AS ( ' +
#sql +
') ' +
'SELECT DISTINCT TableName ' +
'FROM AllTables ';
EXEC (#sql)

Find table name in all objects of all databases

I have a system with multiple databases and client applications. All databases are at one SQL Server instance. They have been developed by different people at different time. So if some error occur it is pritty hard to find in which procedure or trigger the data was modified.
Now I use this script, which I found on this site:
SELECT DISTINCT ISNULL(sd.referenced_schema_name+'.','')+ OBJECT_NAME(sd.referenced_id)TableName,
OBJECT_NAME(sd.referencing_id)Ref_Object,
CASE WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsUserTable')= 1
THEN'Table'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsTableFunction')= 1
THEN'Function'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsTableFunction')= 1
THEN'Function'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsScalarFunction')=1
THEN'Function'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsTrigger')= 1
THEN'Trigger'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsView')= 1
THEN'View'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsUserTable')= 1
THEN'Table'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsProcedure')= 1
THEN'Procedure'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsIndexed')= 1
THEN'Index'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsForeignKey')= 1
THEN'ForeignKey'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsPrimaryKey')= 1
THEN'PrimaryKey'
END AS Ref_Object_Name
FROM sys.sql_expression_dependencies SD
INNER JOIN sys.objects obj
ON obj.object_id=sd.referenced_id
WHERE obj.is_ms_shipped= 0
and referenced_id=object_id('TABLE_NAME') /*Where one can Replace table Name*/
AND obj.type_desc='USER_TABLE'
ORDER BY TableName,Ref_Object,Ref_Object_Name
But this script seems to work only for the database to which the table belong.
I want to get for a specified table name (or even better for an object) list of all objects of all databases in which the specified table name met:
Database_Name SchemaName ObjectName ObjectKind
Thanks.
DECLARE #table_name SYSNAME = N'%';
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += 'SELECT DISTINCT Database_Name = ''' + QUOTENAME(name) + ''',
COALESCE(sd.referenced_schema_name +''.'', '''')+ o.name AS TableName,
r.name AS Ref_Object,
r.type_desc AS Ref_Object_Name
FROM ' + QUOTENAME(name) + '.sys.sql_expression_dependencies AS sd
INNER JOIN ' + QUOTENAME(name) + '.sys.objects AS o
ON o.object_id = sd.referenced_id
INNER JOIN ' + QUOTENAME(name) + '.sys.objects AS r
ON sd.referencing_id = r.object_id
WHERE o.is_ms_shipped = 0
and referenced_id = o.object_id
AND o.type_desc = ''USER_TABLE''
AND o.name LIKE ''' + #table_name + '''
UNION ALL
'
FROM sys.databases
WHERE database_id BETWEEN 5 AND 32766;
SET #sql = LEFT(#sql, LEN(#sql)-11)
+ 'ORDER BY Database_Name, TableName,Ref_Object,Ref_Object_Name';
EXEC sp_executesql #sql;
EDIT
The above will find all the references within each database, but won't find cross-database references. It took a little playing, and the output isn't precisely what you wanted, but I think it makes it more self-explanatory:
DECLARE #table_name SYSNAME = N'%'; -- find all
CREATE TABLE #d
(
db SYSNAME,
[object_id] INT,
sch SYSNAME,
obj SYSNAME,
ref_db NVARCHAR(128),
ref_sch NVARCHAR(128),
ref_obj NVARCHAR(128),
ref_object_id INT,
type_desc SYSNAME
);
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += 'SELECT ''' + QUOTENAME(name) + ''',
d.referencing_id,
QUOTENAME(s.name),
QUOTENAME(o.name),
QUOTENAME(d.referenced_database_name),
QUOTENAME(d.referenced_schema_name),
QUOTENAME(d.referenced_entity_name),
d.referenced_id,
o.type_desc
FROM ' + QUOTENAME(name)
+ '.sys.sql_expression_dependencies AS d
INNER JOIN ' + QUOTENAME(name)
+ '.sys.objects AS o
ON d.referencing_id = o.[object_id]
INNER JOIN '
+ QUOTENAME(name) + '.sys.schemas AS s
ON o.[schema_id] = s.[schema_id]
WHERE d.referenced_entity_name LIKE ''' + #table_name + '''
UNION ALL
'
FROM sys.databases WHERE database_id BETWEEN 5 AND 32766;
SET #sql = LEFT(#sql, LEN(#sql)-11);
INSERT #d EXEC sp_executesql #sql;
SELECT
db+'.'+sch+'.'+obj,
' (' + type_desc + ') references => ',
COALESCE(ref_db, db)+'.'+ref_sch+'.'+ref_obj
FROM #d;
GO
DROP TABLE #d;
GO
Sample output:
[db1].[dbo].[foo] (SQL_STORED_PROCEDURE) references => [db2].[dbo].[bar]
[db1].[dbo].[xyz] (SQL_STORED_PROCEDURE) references => [db1].[dbo].[table_xyz]
This should help you get started
create table ##tbData (
DatabaseName Varchar(64),
objectName varchar(128),
ObjectKind varchar(128)
)
go
EXEC sp_Msforeachdb "use [?];
insert ##tbData select db_name(),so.name,so.xtype from sysobjects so"
select * from ##tbdata
Essentially, build a table and the SQL statement you want to use, then use the undocumented sp_MSforEachdb to load the table from every database
You could look at something like sp_MSForeachdb and call the above query each of those databases.

Is it possible to Add column to multiple table simultaneously?

I am using SQL Server. I want to add a single column named [DateCreated] to multiple tables. Is it possible that with a single statement I could add this column to all the tables in my database?
I stumble upon an answer by Joe Steffaneli in which he suggested a query which in turn returns rows consisting Alter table statements.
Query is as follows :
select 'alter table ' + quotename(s.name) + '.' + quotename(t.name) + ' add [DateModified] datetime'
from sys.columns c
inner join sys.tables t
on c.object_id = t.object_id
inner join sys.schemas s
on t.schema_id = s.schema_id
left join sys.columns c2
on t.object_id = c2.object_id
and c2.name = 'DateModified'
where c.name = 'DateCreated'
and t.type = 'U'
and c2.column_id is null /* DateModified column does not already exist */
Is there any way that I can execute returned rows? Sorry for English.
You probably need something like this. Check that the script does what you want before running it (adds a non null column with a default value of getdate())!
DECLARE #Dynsql nvarchar(max)
SET #Dynsql = ''
SELECT #Dynsql = #Dynsql + '
alter table ' + QUOTENAME(SCHEMA_NAME(schema_id))+ '.' + QUOTENAME(name) +
' add [DateCreated] datetime not null default getdate()'
FROM sys.tables
WHERE type='U' and object_id NOT IN (select object_id from sys.columns where name='DateCreated')
EXEC (#Dynsql)
You can use this query
I use the where clause in this query (it is optional) to find all tables that have ID and add the new field to them.
you can change where clause for example find all tables that have BusinessId column and add new filed or remove where clause and add for all tables
DECLARE #SQL varchar(max)
SELECT #SQL= STUFF((SELECT ';' + 'ALTER TABLE ' + t.TABLE_SCHEMA+'.' +t.TABLE_NAME+ ' ADD newfield nvarchar(max)'
from information_schema.tables t
inner join information_schema.columns c on c.table_name = t.table_name
and c.table_schema = t.table_schema
where c.column_name = 'id'
and t.table_schema not in ('information_schema', 'pg_catalog')
and t.table_type = 'BASE TABLE'
FOR XML PATH('')),1,1,'')
EXEC (#SQL)
This stored procedure works fine
USE databaseName;
exec sp_msforeachtable 'alter table ? Add [DateCreated] datetime not null default getdate()';
declare #i int
set #i=1
while(#i<45)
begin
declare #sql varchar(200)
with TempTable as (select Row_number() over(order by stdID) as RowNo,* from SomeTable)
select #sql= 'alter table Table'+(select Name from TempTable where RowNo=#i)+' add NewColumn int'
exec (#sql)
set #i=#i+1
end
No, there is no single statement that will add a column to all the tables in your database.
Next time please tag your question with the RDBMS you're using. If there were a way, we wouldn't be able to give you the command without knowing which database system you are using.

Resources