Currently i have to create a list of all tables & schemes used in several (terribly) long SQL statements.
Of course i could go manually through the SQL statements and write down every table used in a JOIN, Subselect and so on.
But i'd be curious if there is any easier way to do it. maybe with a "simple" SQL statement, but i have no clue how to do it.
Why am i asking? I'd have to do this for about 50 SQL-Unload-Statements, where all of them use between 30 and 70 tables. I guess you can imagine this quite boring work
Thanks in advance for any input & hints!
Have a read here: How can i get the list of tables in the stored procedure
;WITH stored_procedures AS (
SELECT
o.name AS proc_name, oo.name AS table_name,
ROW_NUMBER() OVER(partition by o.name,oo.name ORDER BY o.name,oo.name) AS row
FROM sysdepends d
INNER JOIN sysobjects o ON o.id=d.id
INNER JOIN sysobjects oo ON oo.id=d.depid
WHERE o.xtype = 'P')
SELECT proc_name, table_name FROM stored_procedures
WHERE row = 1
ORDER BY proc_name,table_name
All credit to the OP of the code above in the thread above.
I will post this answer & mark it as solved, as it was the best and easiest way to solve my issue.
Hint was in a comment by #whereisSQL (thanks a lot!)
Seems like it was already asked in this thread, but i didn't find it:
https://dba.stackexchange.com/questions/121346/need-to-get-identify-all-tables-and-columns-in-a-sql-query/121355#121355
There is an online "get table column" tool to list the tables of a SQL statement here:
http://107.170.101.241:8080/getTableColumn/
It lists all tables and additionally columns used in the statement! Perfect solution in my case.
This may help. Using DMVs
IF EXISTS (
SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[sp_dependsobj]')
AND type IN (
N'P'
,N'PC'
)
)
DROP PROCEDURE [dbo].[sp_dependsobj]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[sp_dependsobj] (#Objname NVARCHAR(2000))
AS
BEGIN
SET NOCOUNT ON
DECLARE #ObjID INTEGER
DECLARE #ObjType VARCHAR(100)
DECLARE #RowCount INTEGER = 0
SELECT #ObjID = OBJECT_ID(#Objname)
SELECT #ObjType = TYPE
FROM sys.objects
WHERE object_id = #ObjID
DECLARE #RefObjects AS TABLE (
[Object_name] SYSNAME
,[Type] VARCHAR(255)
,referenced_entity_name SYSNAME
,Column_name SYSNAME NULL
,referenced_entity_type VARCHAR(255)
)
DECLARE #FoundIn AS TABLE (
[Object_name] SYSNAME
,[Found In] SYSNAME
,[Type] VARCHAR(255)
)
DECLARE #SQLStr VARCHAR(MAX)
SET #SQLStr = '
WITH CTE_Objects
AS
(
SELECT o.NAME referencing_entity_name
,o.type_desc referencing_object_type
,sed.referenced_entity_name
,refobj.referenced_minor_name
,obj.type_desc
,obj.object_id
FROM sys.sql_expression_dependencies sed
INNER JOIN sys.objects o ON sed.referencing_id = o.[object_id]
INNER JOIN sys.objects obj ON sed.referenced_entity_name = obj.name
INNER JOIN sys.dm_sql_referenced_entities(''dbo.' + #Objname + ''', ''OBJECT'') refobj ON
refobj.referenced_id = sed.referenced_id
WHERE o.NAME = ''' + #Objname + '''
UNION
SELECT ''' + #Objname + ''', (SELECT type_desc from sys.objects where name = ''' + #Objname + '''), referenced_entity_name, NULL, obj.type_desc
,obj.object_id
FROM sys.dm_sql_referenced_entities (''dbo.' + '' + #Objname +
''', ''OBJECT'') refObj INNER JOIN sys.objects obj
ON refObj.referenced_entity_name = obj.name
)
SELECT CTE.referencing_entity_name Object_name, CTE.referencing_object_type Type, CTE.referenced_entity_name, CTE.referenced_minor_name Column_name, CTE.type_desc referenced_entity_type
FROM CTE_Objects CTE LEFT JOIN sys.columns cl ON
cte.object_id = cl.object_id AND cte.referenced_minor_name = cl.name
Order by cte.referencing_entity_name, CASE WHEN cte.referencing_entity_name IS NULL THEN 0 ELSE cl.column_id END
'
INSERT INTO #RefObjects (
[Object_name]
,[Type]
,referenced_entity_name
,Column_name
,referenced_entity_type
)
EXEC (#SQLStr)
SET #RowCount = ##ROWCOUNT
IF #RowCount > 0
BEGIN
SELECT *
FROM #RefObjects
END
SET #SQLStr = '
SELECT DISTINCT [Object Name] = o.NAME
,[Found In] = sp.NAME
,sp.type_desc Type
FROM sys.objects o
INNER JOIN sys.sql_expression_dependencies sd ON o.object_id = sd.referenced_id
INNER JOIN sys.objects sp ON sd.referencing_id = sp.object_id
WHERE o.NAME = ''' + #Objname + '''
UNION
SELECT ''' + #Objname + ''', referencing_entity_name, (SELECT type_desc from sys.objects where name = referencing_entity_name)
FROM sys.dm_sql_referencing_entities (''dbo.' + '' + #Objname + ''', ''OBJECT'');
'
INSERT INTO #FoundIn (
[Object_name]
,[Found In]
,[Type]
)
EXEC (#SQLStr)
SET #RowCount = ##ROWCOUNT
IF #RowCount > 0
BEGIN
SELECT *
FROM #FoundIn
END
IF NOT EXISTS (
SELECT 1
FROM #RefObjects
)
AND NOT EXISTS (
SELECT 1
FROM #FoundIn
)
BEGIN
PRINT 'Object does not reference any object, and no objects reference it.'
END
SET NOCOUNT OFF
END
GO
The question is old, but here is a regex for those that want the tables used in SQL statement (From/join).
I created it specially for my case, but it may be adapt and useful for others:
(from|join)[ ]{1,}[^.\n\ ]+?(?=(.))[.].*?(?=( |\n))
Related
I'm trying to iterate through all databases by listing all table constraints. I've achieved the following:
DECLARE #sql nvarchar(max) = ''
SET #sql =
'
USE ?
select con.[name] as constraint_name,
schema_name(t.schema_id) + ''.'' + t.[name] as [table],
col.[name] as column_name,
con.[definition],
case when con.is_disabled = 0
then ''Active''
else ''Disabled''
end as [status]
from sys.check_constraints con
left outer join sys.objects t
on con.parent_object_id = t.object_id
left outer join sys.all_columns col
on con.parent_column_id = col.column_id
and con.parent_object_id = col.object_id
order by con.name
'
PRINT #sql
EXEC sp_MSforeachdb #sql
I would like to have the query UNION all of my results in one clean select.
Can anyone help?
Using SQL Server 2016.
One way is to insert the intermediate results into a temp table. Below is an example that also includes the database name in the results.
CREATE TABLE #results (
[database_name] sysname
,[constraint_name] nvarchar(128)
,[table] nvarchar(257)
,[column_name] nvarchar(128)
,[definition] nvarchar(max)
,[status] varchar(8)
);
DECLARE #sql nvarchar(max) = ''
SET #sql =
N'
USE [?];
INSERT INTO #results
select
N''?'' as database_name,
con.[name] as constraint_name,
schema_name(t.schema_id) + ''.'' + t.[name] as [table],
col.[name] as column_name,
con.[definition],
case when con.is_disabled = 0
then ''Active''
else ''Disabled''
end as [status]
from sys.check_constraints con
left outer join sys.objects t
on con.parent_object_id = t.object_id
left outer join sys.all_columns col
on con.parent_column_id = col.column_id
and con.parent_object_id = col.object_id;
';
PRINT #sql;
EXEC sp_MSforeachdb #sql;
SELECT * FROM #results;
I'm trying to make a query that return the name of all columns for a table, and for each columns the count distinct. I have more than 1400 tables to test, with some with 100 columns, so I can't imagine tiping colomn names one by one.
I have problem for the count disctinct part, And I whant to know if it is possible to do something like an EXECUTE IMMEDIATE in a subquery, and if no, if there is an other solution ?
Here is my actual query :
SELECT
sc.name AS columnName
, ('SELECT COUNT(DISTINCT ' || sc.name || ') FROM MyTableName') AS nb_distinct_row
FROM dbo.syscolumns sc INNER JOIN sysobjects so
ON so.id = sc.id
AND so.name = 'MyTableName'
GROUP BY sc.name
This return the good subquery but I don't know how to execute it immediatly ?
I've tried something like
, (SELECT count(distinct sc.name) from MyTableName) As nbDistinctRow
But the 'sc.name' is not interpreted and the count distinct return 1, so that's why I'm trying this way.
I work on a sybase IQ Database
Anyone can help me ?
thank you in advance.
I have found a way to make this work, but it's realy clumsy.
CREATE OR REPLACE PROCEDURE FLA_distinctCols(in table_obj_id INT)
RESULT (column_name VARCHAR(128), count_distinct INT)
BEGIN
DECLARE err_notfound EXCEPTION FOR SQLSTATE VALUE '02000';
DECLARE #tablename VARCHAR(100);
DECLARE #cols VARCHAR(128);
DECLARE #nb_dist INT;
DECLARE #sql VARCHAR(30000);
DECLARE #sqltemp VARCHAR(30000);
DECLARE tables NO SCROLL CURSOR FOR
SELECT
sc.name col
, ('SELECT COUNT(DISTINCT ' || sc.name || ') INTO #nb_dist FROM ' || #tablename)
FROM dbo.syscolumns sc INNER JOIN sysobjects so
ON so.id = sc.id
AND so.name = #tablename
|| '%' ORDER BY sc.name
;
SELECT so.name INTO #tablename FROM sysobjects so WHERE so.id = table_obj_id;
create table #tablestats (
column_name varchar(128) not null,
count_distinct INT,
);
open tables WITH HOLD;
LoopTables: loop
fetch next tables into #cols, #sqltemp;
if sqlstate = err_notfound then
leave LoopTables
else
EXECUTE IMMEDIATE WITH QUOTES #sqltemp;
set #sql= 'INSERT INTO #tablestats SELECT ''' || #cols || ''', ' || #nb_dist || ';';
EXECUTE IMMEDIATE WITH QUOTES #sql;
end if
end loop LoopTables;
close tables;
SELECT column_name, count_distinct FROM #tablestats ORDER BY count_distinct DESC;
END
GO
BEGIN
DECLARE #tablename VARCHAR(128);
DECLARE #tableid INT;
SET #tablename = 'Mytablename';
SELECT so.id INTO #tableid FROM sysobjects so WHERE so.name = #tablename;
SELECT * FROM FLA_distinctCols(#tableid);
END
Any other solution ?
I'm new to MsSql and I'm not sure if this can be done but I figured I'd ask before I want on my way with the current process..
I need to create a script that loops through all tables in a database and deletes the rows where CorporationId = "xxx". There are a few tables that do not have this column, but of my ~50 tables, only 1 or two do not.
I can individually delete the records in the table with this:
USE MyDatabase
DECLARE #CorporationId UniqueIdentifier
DECLARE #TokenId UniqueIdentifier
DECLARE #CompanyCode nChar(3)
SET #CorporationId = '52D3AEFE-8EBD-4669-8096-4596FE83BB36'
print 'Starting Web.GasOrder'
DELETE FROM Web.GasOrder
WHERE CorporationId = #CorporationId
print 'Starting Web.GasOrderNumber'
DELETE FROM Web.GasOrderNumber
WHERE CorporationId = #CorporationId
etc..
But this is getting tedious creating one for each table.
Of course, some of the tables have relationships on them.
Is there an easy way to do this or do I need to do it manually for each table?
UPDATE
Most of the options that I have tried run into problems with relationships and give me an error.
sp_MSForEachTable is an undocumented stored procedure which will run a command for each table in the database:
USE MyDatabase
DECLARE #CorporationId VARCHAR(50)
SET #CorporationId = '52D3AEFE-8EBD-4669-8096-4596FE83BB36'
DECLARE #Sql VARCHAR(MAX)
SET #Sql = '
IF COL_LENGTH(''?'',''CorporationId'') IS NOT NULL
BEGIN
DELETE FROM Web.?
WHERE CorporationId = ''' + #CorporationId + '''
END
'
EXEC sp_MSForEachTable #Sql
Here's another one... could easily be changed to a stored procedure...
Declare #corpID Nvarchar(256)
Set #corpID = 'xxx'
If Object_ID('tempdb..#tables') Is Not Null Drop Table #tables
Create Table #tables (tID Int, SchemaName Nvarchar(256), TableName Nvarchar(256))
Insert #tables
Select Row_Number() Over (Order By s.name, so.name), s.name, so.name
From sysobjects so
Join sys.schemas s
On so.uid = s.schema_id
Join syscolumns sc
On so.id = sc.id
Where so.xtype = 'u'
And sc.name = 'CorporationId'
Declare #SQL Nvarchar(Max),
#schema Nvarchar(256),
#table Nvarchar(256),
#iter Int = 1
While Exists (Select 1
From #tables)
Begin
Select #schema = SchemaName,
#table = TableName
From #tables
Where tID = #iter
If Exists (Select 1
From sysobjects o
Join sys.schemas s1
On o.uid = s1.schema_id
Join sysforeignkeys fk
On o.id = fk.rkeyid
Join sysobjects o2
On fk.fkeyid = o2.id
Join sys.schemas s2
On o2.uid = s2.schema_id
Join #tables t
On o2.name = t.TableName Collate Database_Default
And s2.name = t.SchemaName Collate Database_Default
Where o.name = #table
And s1.name = #schema)
Begin
Update t
Set tID = (Select Max(tID) From #tables) + 1
From #tables t
Where tableName = #table
And schemaName = #schema
Set #iter = #iter + 1
End
Else
Begin
Set #Sql = 'Delete t
From [' + #schema + '].[' + #table + '] t
Where CorporationId = ''' + #corpID + ''''
Exec sp_executeSQL #SQL;
Delete t
From #tables t
Where tableName = #table
And schemaName = #schema
Set #iter = #iter + 1
End
End
You could run a query like this:
SELECT 'DELETE FROM [' + s.name + '].[' + t.name + '] WHERE CorporationId = ''52D3AEFE-8EBD-4669-8096-4596FE83BB36'''
FROM sys.columns c
inner join sys.tables t
ON t.object_id= c.object_id
inner join sys.schemas s
ON s.schema_id = t.schema_id
where c.name = 'CorporationId'
and then either copy and paste the results into a new query window and execute the new query or iterate over the results with a cursor and execute each result with the exec statement.
Here is a Sql Fiddle that proves the below query
You can get the tables from this query:
SELECT Name, IsChecked = 0
INTO #Tables
FROM sys.Tables
WHERE EXISTS
(
SELECT * FROM sys.columns
WHERE object_id = OBJECT_ID(sys.Tables.Name) AND sys.columns.Name = 'blah'
)
Then, you can create a dynamic query and execute it for the tables that you found
WHILE(SELECT COUNT(*) FROM #Tables WHERE IsChecked = 0) > 0
BEGIN
SELECT TOP 1 #TableName = Name FROM #Tables WHERE IsChecked = 0
SET #DeleteQuery = 'DELETE FROM ' + #TableName + ' WHERE CorporationID = ''' + #CorporationId + ''''
EXECUTE sp_executeSQL #DeleteQuery;
UPDATE #Tables SET IsChecked = 1 WHERE Name = #TableName
END
I'm changing from local time to UTC-time in our database.
There are alot of triggers that copies information to history tables that currently uses GETDATE().
I would like to find every trigger that uses GETDATE() (instead of GETUTCDATE()) in the database, is there any way to do this automatic?
I've listed them by select * from sys.triggers but I also need to see the actual code to be able to find the use of GETDATE().
Your could try the following:
SELECT o.[name],
c.[text]
FROM sys.objects AS o
INNER JOIN sys.syscomments AS c
ON o.object_id = c.id
WHERE o.[type] = 'TR'
Here's the script I used to export triggers:
DECLARE #t VARCHAR (MAX)
SET #t = ''
SELECT #t = #t + 'IF EXISTS (SELECT 1 FROM sys.triggers WHERE object_id = OBJECT_ID(N''' + s.name + '.' + o.name +'''))
DROP TRIGGER ' + s.name + '.' + o.name + '
GO
' + OBJECT_DEFINITION (OBJECT_ID( s.name + '.' + o.name )) +'
GO
'
FROM sys.objects o
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
INNER JOIN sys.objects o2 ON o.parent_object_id = o2.object_id
WHERE o. [type] = 'TR'
AND (
OBJECTPROPERTY ( o.object_id , 'ExecIsInsertTrigger' ) = 1
OR
OBJECTPROPERTY ( o.object_id , 'ExecIsUpdateTrigger' ) = 1
OR
OBJECTPROPERTY ( o.object_id , 'ExecIsDeleteTrigger' ) = 1
)
SELECT #t AS [processing-instruction(x)] FOR XML PATH ('')
More details here if it doesn't make sense to anyone:
http://paulfentonsql.co.uk/2015/09/01/generate-createdrop-statements-for-all-triggers-of-a-given-type/
If you want to export all triggers from the database... here's some code:
DECLARE #vchServerName VARCHAR(500)
DECLARE #vchDBName VARCHAR(500)
DECLARE #intLoop INTEGER
DECLARE #intTotalRows INTEGER
DECLARE #intId INTEGER
DECLARE #vchName VARCHAR(500)
DECLARE #vchSQL VARCHAR(4000)
-- supress count (just so log looks nicer!)
SET NOCOUNT ON
-- get current DB and server
SET #vchDBName = DB_NAME()
SET #vchServerName = ##servername
-- get list of XXX
SELECT ROW_NUMBER() OVER (ORDER BY o.object_id ) fldRowNum
,o.object_id fldId
,s.name + '.' + o.name fldName
INTO #tblFound
FROM sys.objects o
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE [type] = 'TR'
SET #intTotalRows = ##ROWCOUNT
SET #intLoop = 1
-- loop thru list
WHILE #intLoop <= #intTotalRows
BEGIN
SELECT #intID = fldId
,#vchName = fldName
FROM #tblFound
WHERE fldRowNum = #intLoop
PRINT 'Exporting ' + #vchName + '...'
-- NOTE: I'm using a version of bcp that doens't have -D parameter so I need to use DB name here
SET #vchSQL = 'SELECT c.[text] FROM ' + #vchDBName + '.sys.syscomments AS c WHERE c.id = ' + CONVERT(VARCHAR,#intID)
SET #vchSQL = 'bcp "' + #vchSQL + '" queryout "c:\temp\' + #vchName + '.sql" -c -t -T -S ' + #vchServerName
EXEC master..XP_CMDSHELL #vchSQL
SET #intLoop = #intLoop + 1
END
DROP TABLE #tblFound
PRINT 'Done'
SNAHi
anyone please suggest a query in sql to find the unused tables.
I have a legacy application migrated to .net from coldfusion.But lots of tables are unused now
What is the best way to find all the unused objects from database. (sql 2005)
thanks
SNA
In SQL Server, the acutal table data IS the clustered index. Using this query on the Dynamic Management Views (DMV) in SQL Server 2005 and up, you can find unused indices - if you find any clustered index (index_id=1) being unused over an extended period of time, the table is not being used anymore:
DECLARE #dbid INT
SELECT #dbid = DB_ID(DB_NAME())
SELECT
OBJECTNAME = OBJECT_NAME(I.OBJECT_ID),
INDEXNAME = I.NAME,
I.INDEX_ID
FROM
SYS.INDEXES I
JOIN
SYS.OBJECTS O ON I.OBJECT_ID = O.OBJECT_ID
WHERE
OBJECTPROPERTY(O.OBJECT_ID, 'IsUserTable') = 1
AND I.INDEX_ID NOT IN
(SELECT S.INDEX_ID
FROM SYS.DM_DB_INDEX_USAGE_STATS S
WHERE S.OBJECT_ID = I.OBJECT_ID
AND I.INDEX_ID = S.INDEX_ID
AND DATABASE_ID = #dbid)
ORDER BY
OBJECTNAME,
I.INDEX_ID,
INDEXNAME ASC
Another option would be to temporarily rename a table if you suspect it's not being used, and then see if your app(s) still work as expected. If they do for e.g. 30 days or so, then you're pretty sure you don't need that table anymore.
Marc
-- Query to find the tables not used by any stored procedure, function nor view
-- Using SQL 2005 system tables, all programatical objects for dependencies, and one&only query:
select tables.name, progr.name
from sys.objects tables (nolock)
left join sys.syscomments comm (nolock) on comm.text like '%' + tables.name +'%'
left join sys.objects progr (nolock) on progr.object_id = comm.id and progr.type in ('P', 'FN', 'TR', 'V' )
where tables.type = 'U'
and comm.id is null
Here is a query i have written to find the tables not used by any store procedures..
......................................................................................
Declare #tablename nvarchar(40)
Declare tablecursor cursor for
Select name from sysobjects where xtype = 'U'
DECLARE #sqlCommand nvarchar(1000)
declare #rowCount int
DECLARE #searchstring varchar(50)
DECLARE #ParmDefinition nvarchar(500);
create table #temp
(
UnusedTables nvarchar(40)
)
open tablecursor
fetch next from tablecursor into #tablename
while ##fetch_status = 0
begin
set #searchstring='p'
SET #sqlCommand = N'SELECT #rows = count(o.name) from sysobjects o ,
syscomments c where o.type='+char(39)+#searchstring + char(39)+' and
o.id=c.id and c.text like '+ char(39)+'%' + #tablename +'%'+char(39);
SET #ParmDefinition = N'#rows int OUTPUT';
EXECUTE sp_executesql #sqlCommand, #ParmDefinition,#rows=#rowCount OUTPUT;
if #rowCount = 0
begin
insert into #temp values (#tablename)
end
fetch next from tablecursor into #tablename
end
close tablecursor
deallocate tablecursor
select UnusedTables from #temp
drop table #temp
thanks
SA
Try something like below
DECLARE #TableNameTemp TABLE
(
id INT IDENTITY (1, 1),
tablename VARCHAR(1000)
)
INSERT INTO #TableNameTemp
SELECT table_name
FROM information_schema.tables
WHERE table_type = 'BASE TABLE'
ORDER BY table_name
DECLARE #CursorTestID INT = 1;
DECLARE #TotalCount INT = (SELECT Count(1)
FROM #TableNameTemp)
DECLARE #FinalResult TABLE
(
unsedtables VARCHAR(max)
)
DECLARE #TemExecInsert TABLE
(
testvalue VARCHAR(max),
type VARCHAR(max)
)
DECLARE #TableaName VARCHAR(max) = ''
WHILE #CursorTestID <= #TotalCount
BEGIN
DELETE FROM #TemExecInsert
SET #TableaName = (SELECT tablename
FROM #TableNameTemp
WHERE id = #CursorTestID)
INSERT INTO #TemExecInsert
EXEC Sp_depends
#objname = #TableaName
SET #CursorTestID = #CursorTestID + 1
IF ( (SELECT Count(1)
FROM #TemExecInsert) = 0 )
BEGIN
INSERT INTO #FinalResult
VALUES (#TableaName)
END
END
SELECT *
FROM #FinalResult
PS: Sorry, I am not certain how to bring the answer in shape. Hope this helps