auto pick schema change of underlying table for view - sql-server

I know that the sql server doesnt pick the schema change of underlying table. for example, if we execute the following,
CREATE TABLE tbl (id INT)
CREATE VIEW viewa
AS
SELECT *
FROM tbl
ALTER TABLE tbl ADD NAME INT
and execute a select on view, only ID column is returned
SELECT *
FROM viewa
Is there any property I can set by which the sql engine autopicks the schema changes

use sp_refreshview for this,
exec sp_refreshview N'dbo.viewa'

There's no out of the box functionality for this. But you could roll your own. The system tables detail all the columns currently attached to each view and table.
-- Returns every column for the given table/view.
SELECT
c.*
FROM
sys.objects AS o
INNER JOIN sys.schemas AS s ON s.schema_id = o.schema_id
INNER JOIN sys.columns AS c ON c.object_id = o.object_id
WHERE
s.name = 'MySchema'
AND o.name = 'MyTable'
;
You would need to create a control table that maps your tables to views. You would also need to schedule the process.

You can create view with "SCHEMABINDING" option. That way base table definition cannot be modified in a way that could affect view definition.
CREATE VIEW viewa
AS
SELECT *
FROM tbl SCHEMABINDING

Related

Is there a way to check if an object is a table or a view in SQL Server?

I have a view that I am changing to a table in SQL Server.
I am dropping the view and then the next part of my code I am establishing the table.
My code works the first time I run it (when the object is a view), but when I need to run it multiple times, I get this error:
Cannot use DROP VIEW with 'engineer.Well' because 'engineer.Well' is a table. Use DROP TABLE.
I've been looking online but cannot find a way to check if an object is a table or a view, and the subsequently drop the object.
Any advice would be greatly appreciated.
Right now it looks like this,
IF OBJECT_ID('engineer.well') IS NOT NULL
BEGIN
DROP TABLE [engineer].[Well]
PRINT '<<< DROPPED TABLE Vendor >>>'
END
I am playing around with a way to check if the object is a table and then drop it, or check if it is a view then drop it.
You can query the system views.
DECLARE #Type varchar(2)
SELECT #Type = type
FROM sys.objects o
JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.name = 'well'
AND s.name = 'engineer'
IF #Type = 'U'
BEGIN
DROP TABLE [engineer].[Well]
PRINT '<<< DROPPED TABLE Vendor >>>'
END
IF #Type = 'V'
BEGIN
DROP VIEW [engineer].[Well]
PRINT '<<< DROPPED VIEW Vendor >>>'
END
OBJECTPROPERTY(OBJECT_ID('name'), 'IsView')
https://learn.microsoft.com/en-us/sql/t-sql/functions/objectproperty-transact-sql?view=sql-server-2017
or
SELECT id, type FROM sysobjects where id=OBJECT_ID('objectName')
You can query sys.objects table:
select type_desc, * from sys.objects where object_id = object_id('[dbo].[DimDates]')

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

Check for usage of an XML Schema Collection?

As part of a script, in which execution is halted and changes are rolled back if there are any errors, I use the following statements to drop an xml schema collection if it exists
IF EXISTS (SELECT * FROM sys.xml_schema_collections WHERE name = 'MyXMLSchemaCollection')
BEGIN
PRINT 'Drop MyXMLSchemaCollection';
DROP XML SCHEMA COLLECTION MyXMLSchemaCollection;
END
GO
This works nicely except for when the schema collection is in use, the result of which is an error like the following:
Specified collection 'MyXMLSchemaCollection' cannot be dropped because it is used by object 'MyObject'.
How would I go about only dropping the schema collection if it is not used by any objects in the database? The xml schema collection does not need to be dropped if it's being used.
Using the example XML Schema Collection from MSDN documentation ALTER XML SCHEMA COLLECTION (Transact-SQL) I found that you can determine if an XML Schema Collection is being referenced by a table using:
select distinct t.name from sys.tables t
left join sys.columns c ON c.object_id = t.object_id
left join sys.xml_schema_collections x ON x.xml_collection_id = c.xml_collection_id
where x.name = 'MyXMLSchemaCollection'
Also for stored procedures and I imagine other object types sys.sql_expression_dependencies table will be of use to you.
select
*
from sys.sql_expression_dependencies sed
left join sys.objects o ON o.object_id = sed.referencing_id
where referenced_entity_name = 'MyXMLSchemaCollection'
Have a look at these questions for more information on exploring object catalogs:
List of Stored Procedure from Table
Find all references to an object in an SQL Server database

How can i join sys.columns of view to sys.columns of the table it is referencing in T-SQL?

I am trying to join records in sys.columns for a view, to the records in sys.columns for the table it is referencing, because i need the values of is_nullable, is_computed and default_object_id columns for the columns that are selected in the view.
The sys.columns records for the view have "incorrect" values, which you can observe by running the example queries below:
CREATE TABLE TestTable (
FieldA int NOT NULL,
FieldB int DEFAULT (1),
FieldC as CONVERT(INT, FieldA + FieldB),
FieldD int NOT NULL
)
GO
CREATE VIEW TestView WITH SCHEMABINDING AS
SELECT FieldA, FieldC as TestC, FieldB + FieldC as TestD
FROM dbo.TestTable WHERE FieldD = 1
GO
SELECT OBJECT_NAME(c.object_id) as ViewName, c.name as ColumnName,
c.is_nullable as Nullable, c.is_computed as Computed,
cast(CASE WHEN c.default_object_id > 0 THEN 1 ELSE 0 END as bit) as HasDefault
FROM sys.columns c
WHERE object_id = OBJECT_ID('TestTable')
GO
SELECT OBJECT_NAME(c.object_id) as ViewName, c.name as ColumnName,
c.is_nullable as Nullable, c.is_computed as Computed,
cast(CASE WHEN c.default_object_id > 0 THEN 1 ELSE 0 END as bit) as HasDefault
FROM sys.columns c
WHERE object_id = OBJECT_ID('TestView')
GO
I have tried using system views to join on dependencies, but they do not give us information about which column in the view refers to which column in the table:
-- dm_sql_referenced_entities gives us all columns referenced, but all records
-- have referencing_minor_id 0, so we do not know which column refers to what
SELECT * FROM sys.dm_sql_referenced_entities('dbo.TestView', 'OBJECT')
GO
-- sql_dependencies gives us all columns referenced, but all records has
-- column_id 0 so we can not use this either of joining the columns
SELECT * FROM sys.sql_dependencies WHERE object_id = OBJECT_ID('TestView')
GO
-- sql_expression_dependencies just tells us what table we are referencing
-- if view is not created WITH SCHEMABINDING. If it is, it will return columns,
-- but with referencing_minor_id 0 for all records, so not able use this either
SELECT * FROM sys.sql_expression_dependencies
WHERE referencing_id = OBJECT_ID('TestView')
GO
This unanswered post on social.msdn submitted by someone seems to be the same issue:
http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/4ae5869f-bf64-4eef-a952-9ac40c932cd4
You said "i need to know that TestView TestC refers to a computed column". This is not supported by SQL Server 2008 R2 (not sure for 2012 though, but i doubt it).
First you can query sys.columns or INFORMATION_SCHEMA.COLUMNS and you won't find what you want.
If you dig deeper, you will most probably try sys.sql_expression_dependencies and sys.dm_sql_referenced_entities (N'dbo.TestView', N'OBJECT'), but you can find table-column mapping there, not column-column. SQL server stores dependency information by 'high level' object (table, trigger...), not by its details (column). You will find same in sys.sysdepends. As a matter of fact dependency information is in SQL server unreliable.
At last, your only possibility would be to parse the view body by yourself. It can be found in sys.sql_modules:
SELECT m.definition
FROM
sys.objects o
JOIN sys.sql_modules m
ON m.object_id = o.object_id
WHERE
o.object_id = object_id('dbo.TestView')
and o.type = 'V'
Parsing T-SQL is VERY hard, it could really push you to the limit of your efforts. For instance, it should be more or less easy to grab table references from the view, and then table columns, especially if your view is schema-bound. But if it's not, well... just think of asterisks that reference OUTER APPLY, which references recursive CTE...
Anyway, good luck!
Currently, when views are created there are two operations that happen at a high level - parsing & binding. Parsing is basically checking for syntax of the statement, keywords & such. Binding is the process of mapping the identifiers (object names, column names) in the statement to the corresponding objects (tables, views, functions, columns etc.) & derivation of types. Additionally, in case of view similar to SELECT statements you can optionally alias column references and expressions in the SELECT list or after the view name (ex: create view v1(a) as select i from t).
After binding, we persist only the column aliases & the derived types in the metadata since a view is logically a table derived from a query expression. So there is currently no way to determine the expression that the column aliases map to or what it contains (columns or functions or literals etc.)
Only way to obtain the information you are looking for is to parse the view definition & perform your own binding. I believe we already have a bug that tracks the feature request to expose more richer dependency information regarding the mapping of aliases to column expressions in view definitions.
Lastly, SQL Server Developer Studio or Visual Studio Database Project uses the managed T-SQL parser to track such references so you can do refactoring or renaming for example using the project.
Hope this helps clarify the problem/current implementation.
It seems like the misunderstanding is the assumption that object_id is a primary key in sys.columns. It is not. The object_id in sys.columns relates to the object_id in sys.objects.
So:
SELECT C.*
FROM sys.objects T
INNER JOIN sys.columns C
ON T.object_id = C.object_id
WHERE T.type in ('S','U') -- System Tables and User Tables
AND T.name = 'Address' -- Table Name
order by C.Column_ID
will return the columns in the "Address" table in AdventureWorks.

How to find all trigger associated with a table with SQL Server?

I created a trigger for a table in SQL Server and it works for me.
My problem is: How do find it and modify it?
I use this query to find my triggers:
select * from sys.triggers
This find all triggers, but how to open it and change the triggers?
You can do this simply with SSMS. Just go to your table name and expand the Triggers node to view a list of triggers associated with that table. Right click to modify your trigger.
select so.name, text
from sysobjects so, syscomments sc
where type = 'TR'
and so.id = sc.id
and text like '%YourTableName%'
This way you can list out all the triggers associated with the given table.
This might be useful
SELECT
t.name AS TableName,
tr.name AS TriggerName
FROM sys.triggers tr
INNER JOIN sys.tables t ON t.object_id = tr.parent_id
WHERE
t.name in ('TABLE_NAME(S)_GOES_HERE');
This way you just have to plugin the name of tables and the query will fetch all the triggers you need
select m.definition from sys.all_sql_modules m inner join sys.triggers t
on m.object_id = t.object_id
Here just copy the definition and alter the trigger.
Else you can just goto SSMS and Expand the your DB and under Programmability expand Database Triggeres then right click on the specific trigger and click modify there also you can change.
use sp_helptrigger to find the triggerlist for the associated tables
find triggers on table:
select so.name, text
from sysobjects so, syscomments sc
where type = 'TR'
and so.id = sc.id
and text like '%TableName%'
and you can find store procedure which has reference of table:
SELECT Name
FROM sys.procedures
WHERE OBJECT_DEFINITION(OBJECT_ID) LIKE '%yourtablename%'
Go through
Need to list all triggers in SQL Server database with table name and table's schema
This URL have set of queries by which you can get the list of triggers associated with particular table.
I believe you are working in sqlserver following are the steps to get modify triggers
To modify a trigger
Expand a server group, and then expand a server.
Expand Databases, expand the database in which the table containing
the trigger belongs, and then click Tables.
In the details pane, right-click the table on which the trigger
exists, point to All Tasks, and then click Manage Triggers.
In Name, select the name of the trigger.
Change the text of the trigger in the Text field as necessary. Press
CTRL+TAB to indent the text of a SQL Server Enterprise Manager
trigger.
To check the syntax of the trigger, click Check Syntax.
With this query you can find all Trigger in all tables and all views.
;WITH
TableTrigger
AS
(
Select
Object_Kind = 'Table',
Sys.Tables.Name As TableOrView_Name ,
Sys.Tables.Object_Id As Table_Object_Id ,
Sys.Triggers.Name As Trigger_Name,
Sys.Triggers.Object_Id As Trigger_Object_Id
From Sys.Tables
INNER Join Sys.Triggers On ( Sys.Triggers.Parent_id = Sys.Tables.Object_Id )
Where ( Sys.Tables.Is_MS_Shipped = 0 )
),
ViewTrigger
AS
(
Select
Object_Kind = 'View',
Sys.Views.Name As TableOrView_Name ,
Sys.Views.Object_Id As TableOrView_Object_Id ,
Sys.Triggers.Name As Trigger_Name,
Sys.Triggers.Object_Id As Trigger_Object_Id
From Sys.Views
INNER Join Sys.Triggers On ( Sys.Triggers.Parent_id = Sys.Views.Object_Id )
Where ( Sys.Views.Is_MS_Shipped = 0 )
),
AllObject
AS
(
SELECT * FROM TableTrigger
Union ALL
SELECT * FROM ViewTrigger
)
Select
*
From AllObject
Order By Object_Kind, Table_Object_Id
select B.name
from sys.objects A
join sys.triggers B
on A.object_id = B.parent_id
where A.name ='Table_name' /*Table Name*/
select o1.name as trigger_name,o2.name as table_name from sys.objects o1
join sys.objects o2 on
o1.parent_object_id=o2.object_id
where o1.type='TR'
and o2.name='my_table'
You Can View All trigger related to your database by below query
select * from sys.triggers
And for open trigger you can use below syntax
sp_helptext 'dbo.trg_InsertIntoUserTable'
Much simple query below
select (select [name] from sys.tables where [object_id] = tr.parent_id ) as TableName ,* from sys.triggers tr
select * from information_schema.TRIGGERS;
select t.name as TriggerName,m.definition,is_disabled
from sys.all_sql_modules m
inner join
sys.triggers t
on m.object_id = t.object_id
inner join sys.objects o
on o.object_id = t.parent_id
Where o.name = 'YourTableName'
This will give you all triggers on a Specified Table
Try to Use:
select * from sys.objects where type='tr' and name like '%_Insert%'
you can open your trigger with
sp_helptext yourtriggername

Resources