Combine table and views in T-SQL - sql-server

I am looking into extract table name and all related views and schemas in my SQL Server.
Until now I have used this SQL code to do that:
SELECT
t.VIEW_SCHEMA,
t.VIEW_NAME,
t.TABLE_SCHEMA,
t.TABLE_NAME
FROM
INFORMATION_SCHEMA.VIEW_TABLE_USAGE t
WHERE
t.TABLE_NAME = 'MYTABLE'
AND t.VIEW_NAME like '%_something%'
The INFORMATION_SCHEMA.VIEW_TABLE_USAGE seems only to be updated when views actually are used, so when I run my code on a table with have new view definitions or a views has never been used it returns nothing.
I have tried to combine INFORMATION_SCHEMA.VIEWS and INFORMATION_SCHEMA.TABLES but I can't find a key to join on.
I have also tried to look into sys.tables and sys.views but I still haven't found a way to join it.
I really need to get the columns specified in SQL.
Any ideas on how to do that? Maybe my approach is all wrong.

SQL Server offers a few possibilities via sys.sql_expression_dependencies and sys.dm_sql_referencing_entities()
sys.sql_expression_dependencies is easier to use, an example for your purpose would be
select
Schema_Name(v.schema_id) View_Schema, v.name View_Name,
Schema_Name(t.schema_id) Table_Schema, t.name Table_Name
from sys.tables t
join sys.sql_expression_dependencies d on d.referenced_id=t.object_id
join sys.objects v on v.object_id=d.referencing_id and v.type='V'
where
t.name='tablename'
and v.name like '%something%'

Related

Why the warning about VIEW_COLUMN_USAGE.VIEW_SCHEMA?

I recently noticed that the documentation for the INFORMATION_SCHEMA.VIEW_COLUMN_USAGE view at Microsoft's Docs website contains a warning for both the VIEW_SCHEMA and TABLE_SCHEMA columns:
** Important ** only reliable way to find the schema of a object is to query the sys.objects catalog view.
[sic]
There must be a concrete reason for that warning, and only on those two fields. What's the reason for the warning? Is it know under what circumstances can this information_schema view get the schema fields wrong?
I need to know how concerned I should be; and how hard do I need to push for replacing existing code that uses that view.
This may only be a partial answer but perhaps it's sufficient for your or perhaps it can lead someone else to a more complete answer. But I can tell you that:
exec sp_helptext 'information_schema.view_column_usage'
returns:
SELECT
DB_NAME() AS VIEW_CATALOG,
SCHEMA_NAME(v.schema_id) AS VIEW_SCHEMA,
v.name AS VIEW_NAME,
DB_NAME() AS TABLE_CATALOG,
SCHEMA_NAME(t.schema_id) AS TABLE_SCHEMA,
t.name AS TABLE_NAME,
c.name AS COLUMN_NAME
FROM
sys.views v JOIN sys.sql_dependencies d ON d.object_id = v.object_id
JOIN sys.objects t ON t.object_id = d.referenced_major_id
JOIN sys.columns c ON c.object_id = d.referenced_major_id
AND c.column_id = d.referenced_minor_id
WHERE
d.class < 2
As you can see, both view_schema and table_schema utilize schema_name(). And, as described in this question and elsewhere, that function is known to sometimes give different results depending on whether your query is cross-database or whether default schema for your user is different from someone else's.
I've never actually seen an information_schema query give unexpected results in a schema field, and perhaps it's not really possible with the output from sys.views and sys.tables (a null schema_id would create the issue), but this general behavior with schema_name() may have been sufficient for them to give the disclaimer.

How to check a database in SQL to make sure that all of its tables are in use?

I was assigned to see if all of the current tables in a database are used and if not to drop them. These are the steps I have taken so far:
Searched tables names in the program that uses that database to see if a query has been made in the program based on those tables names.
Investigated if a table primary key has been used in any other places such as view or table (Connectivity with other used tables). I used:
SELECT
t.name AS table_name,
SCHEMA_NAME(schema_id) AS schema_name,
c.name AS column_name
FROM
sys.tables AS t
INNER JOIN
sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE
c.name LIKE 'DeflectionId' -- write the column you search here
ORDER BY
schema_name, table_name;
Searched inside all of the stored procedure texts to see if a table name has been used inside them:
SELECT DISTINCT
o.name AS Object_Name,
o.type_desc
FROM
sys.sql_modules m
INNER JOIN
sys.objects o ON m.object_id = o.object_id
WHERE
m.definition LIKE '%\[Test_Results_LU\]%' ESCAPE '\';
or
SELECT name
FROM sys.procedures
WHERE Object_definition(object_id) LIKE '%Test_Results_LU%'
(from this link: Search text in stored procedure in SQL Server )
Used Object Explorer view to see if a table with the similar/same name and size exists in the database.
Do you think there are other ways that I can use to investigate it better?
Are these steps efficient at all? How would you do it?
Those are all reasonable things to check. One more thing to do would be to turn on profiling or auditing, depending on your SQL server version, and actually monitor for the tables being used for a reasonable time period. You may not be able to do that with a production system, and it's still not 100% guaranteed - what if there's an important table that's only queried once a year?
https://dba.stackexchange.com/questions/40960/logging-queries-and-other-t-sql
https://learn.microsoft.com/en-us/sql/relational-databases/security/auditing/view-a-sql-server-audit-log?view=sql-server-2017
One other suggestion before dropping the tables is to explicitly remove access to them (either with DENY/REVOKE or rename them to table-name_purge) for a week or two and see if anyone complains. If they don't, then it's probably safe to make a backup and then drop them.
A couple of other places to check. Both of these rely on data that is
cached automatically by the system
not persisted between restarts
can be dropped at any time.
so absence from these results does not prove that the table is not used but you may find evidence that a table definitely is in use.
SELECT [Schema] = OBJECT_SCHEMA_NAME(object_id),
[ObjectName] = OBJECT_NAME(object_id),
*
FROM sys.dm_db_index_usage_stats
WHERE database_id = DB_ID()
And in the plan cache
USE YourDB
DROP TABLE IF EXISTS #cached_plans, #plans, #results
DECLARE #dbname nvarchar(300) = QUOTENAME(DB_NAME());
SELECT dm_exec_query_stats.creation_time,
dm_exec_query_stats.last_execution_time,
dm_exec_query_stats.execution_count,
dm_exec_query_stats.sql_handle,
dm_exec_query_stats.plan_handle
INTO #cached_plans
FROM sys.dm_exec_query_stats;
WITH distinctph
AS (SELECT DISTINCT plan_handle
FROM #cached_plans)
SELECT query_plan,
plan_handle
INTO #plans
FROM distinctph
CROSS APPLY sys.dm_exec_query_plan(plan_handle);
WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
SELECT cp.*,
st.text,
[Database] = n.value('#Database', 'nvarchar(300)'),
[Schema] = n.value('#Schema', 'nvarchar(300)'),
[Table] = n.value('#Table', 'nvarchar(300)')
INTO #results
FROM #cached_plans cp
JOIN #plans p
ON cp.plan_handle = p.plan_handle
CROSS APPLY sys.dm_exec_sql_text(sql_handle) st
CROSS APPLY query_plan.nodes('//Object[#Database = sql:variable("#dbname") and #Schema != "[sys]"]') qn(n);
SELECT *
FROM #results

SQL Server sp_help to pull out just the columns information

The SP_HELP procedures produces multiple subsets of data and I would only like to have the columns information from that. Is there a way to maybe write a query using sp_help to just pull out that information.
I need to do this to build a metadata database and maintain it on a weekly basis. Any help is appreciated.
Thanks,
RV.
The information you want can be found with:
select * from sys.columns
However, it can be difficult to navigate using just that table. I like to query the schema, tables, and columns views for this.
select
schemas.name as [schema]
,tables.name as [table]
,columns.*
from sys.schemas
join sys.tables on
schemas.schema_id = tables.schema_id
join sys.columns on
tables.object_id = columns.object_id
You can get more information here.
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'SchemaName'
AND TABLE_NAME = 'TableName'
This should work.

Using SQL Server - is there a way to query 'Create view' SQL

I want to know if a certain table dbo.person is being used in any of the database views in my database. There are a lot of views in this database.
I could right click each view "Script View as --> CREATE To" to see the SQL that was used to build this view but this will take a long time.
I am wondering if there is any way to query all of these "create view as" scripts to see if any of them mention my table dbo.person.
I hope this is clear.
You can query the system catalog for views (and use sql_modules to get the view definition) then use the system view sys.sql_expression_dependencies to find which of these views reference dbo.Person:
SELECT ViewName = QUOTENAME(OBJECT_SCHEMA_NAME(v.[object_id])) + '.' + QUOTENAME(v.Name),
m.[Definition]
FROM sys.views AS v
INNER JOIN sys.sql_modules AS m
ON m.[object_id] = v.[object_id]
WHERE EXISTS
( SELECT 1
FROM sys.sql_expression_dependencies AS d
WHERE d.Referenced_id = OBJECT_ID(N'dbo.Person', 'U')
AND v.[object_id] = d.referencing_id
)
ORDER BY ViewName;
There are some small issues with sys.sql_expression_dependencies, but I would still be more inclined to use this than to search for '%person%', since this could bring back 10s, or 100s of extra results, any time a table that contains person (e.g. dbo.PersonAddress) is referenced, or person is used as an alias (SELECT Forename + surname AS Person) etc. It really depends whether you are looking for something that is going to be accurate most of the time, but may, on occasion miss a reference, or whether you need a catch all solution that will bring back extra results.
You could try
select * from INFORMATION_SCHEMA.VIEWS
where VIEW_DEFINITION like '%Person%'
You might need to change the WHERE to dbo.person or [Person]
For a more detailed string search on SQL Server database object definitions please refer to SQL Object Where Used List script
You can simply call like
exec SearchInObjectsText 'name'
and it will return procedures, functions, views, etc where the text "name" is used
I know this doesn't answer the question directly, but it answers the need. I use a third party add-in called SQLSearch from redgate. It's free and I'm not an employee, so this isn't a "plug" of any kind.
I normally use this SQL to look in definitions. I didn't filter on VIEWS just in case it is used somewhere else.
SELECT
so.name, so.type, sm.Definition
FROM
sys.objects AS so INNER JOIN sys.sql_modules AS sm ON so.object_id = sm.object_id
WHERE
sm.Definition LIKE N'%dbo.person%'
ORDER BY so.name
Please query Information_Schema.View_Table system views
select * from INFORMATION_SCHEMA.VIEW_TABLE_USAGE where TABLE_NAME = 'Emp'
Try this
SELECT DISTINCT m.definition, o.name AS Object_Name,o.type_desc
FROM sys.sql_modules m
INNER JOIN sys.objects o
ON m.object_id=o.object_id
WHERE m.definition Like '%person%'
and type_desc = 'VIEW'

SQL Query to search schema of all tables

I am working on a SQL Server 2008 Db that has many tables in it (around 200). Many of these tables contain a field by the name "CreatedDate". I am trying to identify all the table schema with this particular field.
Is there a SQL query to do this?
I would query the information_schema - this has views that are much more readable than the underlying tables.
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%create%'
You can also try doing this using one of many third party tools that are available for this.
Queries are great for simple searches but if you need to do more manipulation with data, search for references and such this is where you can do a much better job with these.
Also, these come in very handy when some objects are encrypted and you need to search for
I’m using ApexSQL Search which is free but there are also many more (also free) on the market such as Red Gate or SSMS Tool Pack.
select object_name(c.object_id) as table_name
, schema_name(t.schema_id) as schema_name
from sys.columns c
join sys.tables t on c.object_id = t.object_id
where c.name=N'CreatedDate';
It gets a little more complicated if you want alsoother table properties, but you'll refer to the object catalog views like sys.tables, sys.columns etc.
My favorite...
SELECT objParent.name AS parent, obj.name, col.*
FROM sysobjects obj
LEFT JOIN syscolumns col
ON obj.id = col.id
LEFT JOIN sysobjects objParent
ON objParent.id = obj.parent_obj
WHERE col.name LIKE '%Comment%'
OR obj.name LIKE '%Comment%'
Above I'm searching for "Comment".
Drop the percent signs if you want a direct match.
This searches tables, fields and things like primary key names, constraints, views, etc.
And when you want to search in StoredProcs after monkeying with the tables (and need to make the procs match), use the following...
SELECT name
FROM sys.procedures
WHERE OBJECT_DEFINITION(OBJECT_ID) LIKE '%Comment%'
Hope that helps, I find these two queries to be extremely useful.
For me I only have read access to run querys so I need to use this function often here is what I use:
SELECT *
FROM INFORMATION_SCHEMA.TABLES
where TABLES.TABLE_NAME like '%your table name here%'
You can replace .TABLES with .COLUMNS then it would look like this:
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE columns.COLUMN_NAME like '%your column name here%'
Use this query :
SELECT
t.name AS table_name,
SCHEMA_NAME(schema_id) AS schema_name,
c.name AS column_name , *
FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
Where
( c.name LIKE '%' + '<ColumnName>' + '%' )
AND
( t.type = 'U' ) -- Use This To Prevent Selecting System Tables
Same thing but in ANSI way
SELECT
*
FROM
INFORMATION_SCHEMA.TABLES
WHERE
TABLE_NAME IN (
SELECT
TABLE_NAME
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
COLUMN_NAME = 'CreateDate'
)
You do not need to type SQL Query for this in SQL Server 2008.
In SSMS Object Explorer choose Databases or Tables of the required database (if you need to search in one database), open menu View--> Object Explorer Details (alternatively press F7), type %CreatedDate% in Search textbox, ENTER, enjoy

Resources