Is it possibile to check who created indexes on SQL Server? I found only script which list time:
select STATS_DATE(so.object_id, index_id) StatsDate
, si.name IndexName
, schema_name(so.schema_id) + N'.' + so.Name TableName
, so.object_id, si.index_id
from sys.indexes si
inner join sys.tables so on so.object_id = si.object_id
order by StatsDate desc
In short, no. But if that's important for you to know for indexes created going forward, you can set up an event notification session or ddl trigger to track that information.
I have a column LastUpdate in all tables of my database and I want to say "on insert of update LastUpdate = getdate()"
I can do this with a trigger but I find it' hard to write hundreds triggers for each table of the database.
- How do I dynamically create a trigger that affect all tables?
- How do I dynamically create triggers for each table ?
It is not possible to have a trigger that fires when any table is updated.
You could generate the SQL Required dynamically, the following:
SELECT N'
CREATE TRIGGER trg_' + t.Name + '_Update ON ' + ObjectName + '
AFTER UPDATE
AS
BEGIN
UPDATE t
SET LastUpdate = GETDATE()
FROM ' + o.ObjectName + ' AS t
INNER JOIN inserted AS i
ON ' +
STUFF((SELECT ' AND t.' + QUOTENAME(c.Name) + ' = i.' + QUOTENAME(c.Name)
FROM sys.index_columns AS ic
INNER JOIN sys.columns AS c
ON c.object_id = ic.object_id
AND c.column_id = ic.column_id
WHERE ic.object_id = t.object_id
AND ic.index_id = ix.index_id
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 4, '') + ';
END;
GO'
FROM sys.tables AS t
INNER JOIN sys.indexes AS ix
ON ix.object_id = t.object_id
AND ix.is_primary_key = 1
CROSS APPLY (SELECT QUOTENAME(OBJECT_SCHEMA_NAME(t.object_id)) + '.' + QUOTENAME(t.name)) o (ObjectName)
WHERE EXISTS
( SELECT 1
FROM sys.columns AS c
WHERE c.Name = 'LastUpdate'
AND c.object_id = t.object_id
);
Generates SQL for each table with a LastUpdate column along the lines of:
CREATE TRIGGER trg_TableName_Update ON [dbo].[TableName]
AFTER UPDATE
AS
BEGIN
UPDATE t
SET LastUpdate = GETDATE()
FROM [dbo].[TableName] AS t
INNER JOIN inserted AS i
ON t.[PrimaryKey] = i.[PrimaryKey];
END;
GO
The relies on each table having a primary key to get the join from the inserted table back to the table being updated.
You can either copy and paste the results and execute them (I would recommend this way so you can at least check the SQL Generated, or build it into a cursor and execute it using sp_executesql. I would recommend the former, i.e. use this to save a bit of time, but still check each trigger before actually creating it.
I personally think last modified columns are a flawed concept, it always feels to me like storing annoyingly little information, if you really care about data changes then track them properly with an audit table (or temporal tables, or using Change Tracking). Firstly, knowing when something was changed, but not what it was changed from, or who changed it is probably more annoying than not knowing at all, secondly it overwrites all previous changes, what makes the latest change more important than all those that have gone before.
I have to change the name and the datatype of a column of a table. I have about 150 stored procedures in the database, out of which about 25 refer to the same column. I need a query that can find the name of all the stored procedures which are dependent on this column.
I use this query:
SELECT OBJECT_NAME(M.object_id), M.*
FROM sys.sql_modules M
JOIN sys.procedures P
ON M.object_id = P.object_id
WHERE M.definition LIKE '%blah%'
Obviously you'd have to substitute "blah" for the name of your column.
Try this 1
From Sp
SELECT Name as [Stored Procedure Name]
FROM sys.procedures
WHERE OBJECT_DEFINITION(OBJECT_ID) LIKE '%getdate%' order by Name
From Table
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 '%EmployeeID%'
ORDER BY schema_name, table_name;
Problem:
As you know there is no way to query what fields are referenced by a function or stored procedure.
The closest we can get is an approximation.
We can tell which tables are referenced and what fields might possibly be referenced by those tables.
For example, if you have "CreatedDate" referenced by the "Person" table and you join to the "Order" table (which also has a "CreatedDate" field), it will find a “false-positive” match to "Order.CreatedDate" when you were only looking for "Person.CreatedDate".
Searching the Text of the object's script for field names is unfortunately the best we can do for now.
The good news is, it won’t miss identifying fields that are actually used.
If anything it might pull in more than what were used (due to shared field names or commented out code).
The only exception would be dynamic SQL, as Tables are not linked to Object Scripts if they are embedded in a dynamic string.
Workaround:
CREATE FUNCTION [dbo].[ft_Schema_Column_Script]
(
#ScriptName nVarChar(128) = '%',
#TableName nVarChar(128) = '%',
#ColumnName nVarChar(128) = '%'
)
RETURNS TABLE
AS
RETURN
(
SELECT ##SERVERNAME[ServerName], DB_NAME()[DatabaseName],
SS.name[ScriptSchemaName], SO.name[ScriptName],
SO.type_desc[ScriptType],
TS.name[TableSchemaName], T.name[TableName], C.name[ColumnName],
UT.name[ColumnType], C.max_length[MaxLength],
C.precision[NumericPrecision], C.scale[Scale],
C.is_nullable[Nullable],
C.is_identity[IsIdentity],
C.column_id[Ordinal],
EP.value[Description]
FROM sys.sql_modules as M
JOIN sys.objects as SO--Script Object.
ON M.object_id = SO.object_id
JOIN sys.schemas as SS--Script Schema.
ON SS.schema_id = SO.schema_id
JOIN sys.sql_expression_dependencies D
ON D.referencing_id = SO.object_id
JOIN sys.tables as T
ON T.object_id = D.referenced_id
JOIN sys.schemas as TS--Table Schema.
ON TS.schema_id = T.schema_id
JOIN sys.columns as C
ON C.object_id = T.object_id
LEFT JOIN sys.types AS UT--Left Join because of user-defined/newer types.
ON UT.user_type_id = C.user_type_id
LEFT JOIN sys.extended_properties AS EP
ON EP.major_id = C.object_id
AND EP.minor_id = C.column_id
AND EP.name = 'MS_Description'
WHERE T.name LIKE #TableName ESCAPE '\'
AND C.name LIKE #ColumnName ESCAPE '\'
AND SO.name LIKE #ScriptName ESCAPE '\'
--Use RegEx to exclude false-posotives by from similar ColumnNames.
-- (e.g. Ignore the "ModifiedBy" field when matching on "Modified").
-- Use C.name instead of #ColumnName to further reduce false-positives.
AND M.definition LIKE ( N'%[ ~`!##$\%\^&*()+-=\[\]\\{}|;'''':",./<>?]'
+ C.name
+ N'[ ~`!##$\%\^&*()+-=\[\]\\{}|;'''':",./<>?]%'
) ESCAPE '\'
)
GO
Test:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT * FROM dbo.ft_Schema_Column_Script('ScriptName', DEFAULT, DEFAULT) as C
SELECT * FROM dbo.ft_Schema_Column_Script(DEFAULT, 'TableName', DEFAULT) as C
SELECT * FROM dbo.ft_Schema_Column_Script(DEFAULT, DEFAULT, 'ColumnName') as C
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
Test the example above to see if it's good enough to meet your needs.
Results:
Example output when running this function searching for the Column Name "Created".
It searches Stored Procedures (Sprocs), User-Defined-Functions (UDF's), Triggers, but not Jobs.
The cool thing is:
This not only searches for Columns referenced by Scripts,but also Scripts referenced by Columns (or Tables)!
-- Search in All Objects
SELECT OBJECT_NAME(OBJECT_ID),
definition
FROM sys.sql_modules
WHERE definition LIKE '%' + 'BusinessEntityID' + '%'
Search in Stored Procedures Only:
SELECT DISTINCT OBJECT_NAME(OBJECT_ID),
object_definition(OBJECT_ID)
FROM sys.Procedures
WHERE object_definition(OBJECT_ID) LIKE '%' + 'BusinessEntityID' + '%'
I have many tables that have a [DateCreated] column that also needs a [DateModified] column.
The [DateModified] column will need an Update trigger that inserts the current date (getdate()) into this new [DateModified] column.
Each table uses custom schema, not [dbo].
Whats the easiest/best way to do this?
This will get you the alter table statements, which you can cut/paste into a new query window to execute. I'll leave it as an exercise for the reader to use this same technique to generate the create trigger statements.
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 */
I'm trying to test if a given default constraint exists. I don't want to use the sysobjects table, but the more standard INFORMATION_SCHEMA.
I've used this to check for tables and primary key constraints before, but I don't see default constraints anywhere.
Are they not there? (I'm using MS SQL Server 2000).
EDIT: I'm looking to get by the name of the constraint.
As I understand it, default value constraints aren't part of the ISO standard, so they don't appear in INFORMATION_SCHEMA. INFORMATION_SCHEMA seems like the best choice for this kind of task because it is cross-platform, but if the information isn't available one should use the object catalog views (sys.*) instead of system table views, which are deprecated in SQL Server 2005 and later.
Below is pretty much the same as #user186476's answer. It returns the name of the default value constraint for a given column. (For non-SQL Server users, you need the name of the default in order to drop it, and if you don't name the default constraint yourself, SQL Server creates some crazy name like "DF_TableN_Colum_95AFE4B5". To make it easier to change your schema in the future, always explicitly name your constraints!)
-- returns name of a column's default value constraint
SELECT
default_constraints.name
FROM
sys.all_columns
INNER JOIN
sys.tables
ON all_columns.object_id = tables.object_id
INNER JOIN
sys.schemas
ON tables.schema_id = schemas.schema_id
INNER JOIN
sys.default_constraints
ON all_columns.default_object_id = default_constraints.object_id
WHERE
schemas.name = 'dbo'
AND tables.name = 'tablename'
AND all_columns.name = 'columnname'
You can use the following to narrow the results even more by specifying the Table Name and Column Name that the Default Constraint correlates to:
select * from sysobjects o
inner join syscolumns c
on o.id = c.cdefault
inner join sysobjects t
on c.id = t.id
where o.xtype = 'D'
and c.name = 'Column_Name'
and t.name = 'Table_Name'
There seems to be no Default Constraint names in the Information_Schema views.
use SELECT * FROM sysobjects WHERE xtype = 'D' AND name = #name
to find a default constraint by name
The script below lists all the default constraints and the default values for the user tables in the database in which it is being run:
SELECT
b.name AS TABLE_NAME,
d.name AS COLUMN_NAME,
a.name AS CONSTRAINT_NAME,
c.text AS DEFAULT_VALUE
FROM sys.sysobjects a INNER JOIN
(SELECT name, id
FROM sys.sysobjects
WHERE xtype = 'U') b on (a.parent_obj = b.id)
INNER JOIN sys.syscomments c ON (a.id = c.id)
INNER JOIN sys.syscolumns d ON (d.cdefault = a.id)
WHERE a.xtype = 'D'
ORDER BY b.name, a.name
If you want to get a constraint by the column or table names, or you want to get all the constraints in the database, look to other answers. However, if you're just looking for exactly what the question asks, namely, to "test if a given default constraint exists ... by the name of the constraint", then there's a much easier way.
Here's a future-proof answer that doesn't use the sysobjects or other sys tables at all:
IF object_id('DF_CONSTRAINT_NAME', 'D') IS NOT NULL BEGIN
-- constraint exists, work with it.
END
select c.name, col.name from sys.default_constraints c
inner join sys.columns col on col.default_object_id = c.object_id
inner join sys.objects o on o.object_id = c.parent_object_id
inner join sys.schemas s on s.schema_id = o.schema_id
where s.name = #SchemaName and o.name = #TableName and col.name = #ColumnName
Is the COLUMN_DEFAULT column of INFORMATION_SCHEMA.COLUMNS what you are looking for?
Necromancing.
If you only need to check if a default-constraint exists
(default-constraint(s) may have different name in poorly-managed DBs),
use INFORMATION_SCHEMA.COLUMNS (column_default):
IF NOT EXISTS(
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE (1=1)
AND TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'T_VWS_PdfBibliothek'
AND COLUMN_NAME = 'PB_Text'
AND COLUMN_DEFAULT IS NOT NULL
)
BEGIN
EXECUTE('ALTER TABLE dbo.T_VWS_PdfBibliothek
ADD CONSTRAINT DF_T_VWS_PdfBibliothek_PB_Text DEFAULT (N''image'') FOR PB_Text;
');
END
If you want to check by the constraint-name only:
-- Alternative way:
IF OBJECT_ID('DF_CONSTRAINT_NAME', 'D') IS NOT NULL
BEGIN
-- constraint exists, deal with it.
END
And last but not least, you can just create a view called INFORMATION_SCHEMA.DEFAULT_CONSTRAINTS:
CREATE VIEW INFORMATION_SCHEMA.DEFAULT_CONSTRAINTS
AS
SELECT
DB_NAME() AS CONSTRAINT_CATALOG
,csch.name AS CONSTRAINT_SCHEMA
,dc.name AS CONSTRAINT_NAME
,DB_NAME() AS TABLE_CATALOG
,sch.name AS TABLE_SCHEMA
,syst.name AS TABLE_NAME
,sysc.name AS COLUMN_NAME
,COLUMNPROPERTY(sysc.object_id, sysc.name, 'ordinal') AS ORDINAL_POSITION
,dc.type_desc AS CONSTRAINT_TYPE
,dc.definition AS COLUMN_DEFAULT
-- ,dc.create_date
-- ,dc.modify_date
FROM sys.columns AS sysc -- 46918 / 3892 with inner joins + where
-- FROM sys.all_columns AS sysc -- 55429 / 3892 with inner joins + where
INNER JOIN sys.tables AS syst
ON syst.object_id = sysc.object_id
INNER JOIN sys.schemas AS sch
ON sch.schema_id = syst.schema_id
INNER JOIN sys.default_constraints AS dc
ON sysc.default_object_id = dc.object_id
INNER JOIN sys.schemas AS csch
ON csch.schema_id = dc.schema_id
WHERE (1=1)
AND dc.is_ms_shipped = 0
/*
WHERE (1=1)
AND sch.name = 'dbo'
AND syst.name = 'tablename'
AND sysc.name = 'columnname'
*/
WHILE EXISTS(
SELECT * FROM sys.all_columns
INNER JOIN sys.tables ST ON all_columns.object_id = ST.object_id
INNER JOIN sys.schemas ON ST.schema_id = schemas.schema_id
INNER JOIN sys.default_constraints ON all_columns.default_object_id = default_constraints.object_id
WHERE
schemas.name = 'dbo'
AND ST.name = 'MyTable'
)
BEGIN
DECLARE #SQL NVARCHAR(MAX) = N'';
SET #SQL = ( SELECT TOP 1
'ALTER TABLE ['+ schemas.name + '].[' + ST.name + '] DROP CONSTRAINT ' + default_constraints.name + ';'
FROM
sys.all_columns
INNER JOIN
sys.tables ST
ON all_columns.object_id = ST.object_id
INNER JOIN
sys.schemas
ON ST.schema_id = schemas.schema_id
INNER JOIN
sys.default_constraints
ON all_columns.default_object_id = default_constraints.object_id
WHERE
schemas.name = 'dbo'
AND ST.name = 'MyTable'
)
PRINT #SQL
EXECUTE sp_executesql #SQL
--End if Error
IF ##ERROR <> 0
BREAK
END
I don't think it's in the INFORMATION_SCHEMA - you'll probably have to use sysobjects or related deprecated tables/views.
You would think there would be a type for this in INFORMATION_SCHEMA.TABLE_CONSTRAINTS, but I don't see one.
Probably because on some of the other SQL DBMSs the "default constraint" is not really a constraint, you'll not find its name in "INFORMATION_SCHEMA.TABLE_CONSTRAINTS", so your best bet is "INFORMATION_SCHEMA.COLUMNS" as others have mentioned already.
(SQLServer-ignoramus here)
The only a reason I can think of when you have to know the "default constraint"'s name is if SQLServer doesn't support "ALTER TABLE xxx ALTER COLUMN yyy SET DEFAULT..." command. But then you are already in a non-standard zone and you have to use the product-specific ways to get what you need.
How about using a combination of CHECK_CONSTRAINTS and CONSTRAINT_COLUMN_USAGE:
select columns.table_name,columns.column_name,columns.column_default,checks.constraint_name
from information_schema.columns columns
inner join information_schema.constraint_column_usage usage on
columns.column_name = usage.column_name and columns.table_name = usage.table_name
inner join information_schema.check_constraints checks on usage.constraint_name = checks.constraint_name
where columns.column_default is not null
I am using folllowing script to retreive all defaults (sp_binddefaults) and all default constraint with following scripts:
SELECT
t.name AS TableName, c.name AS ColumnName, SC.COLUMN_DEFAULT AS DefaultValue, dc.name AS DefaultConstraintName
FROM
sys.all_columns c
JOIN sys.tables t ON c.object_id = t.object_id
JOIN sys.schemas s ON t.schema_id = s.schema_id
LEFT JOIN sys.default_constraints dc ON c.default_object_id = dc.object_id
LEFT JOIN INFORMATION_SCHEMA.COLUMNS SC ON (SC.TABLE_NAME = t.name AND SC.COLUMN_NAME = c.name)
WHERE
SC.COLUMN_DEFAULT IS NOT NULL
--WHERE t.name = '' and c.name = ''
Object Catalog View : sys.default_constraints
The information schema views INFORMATION_SCHEMA are ANSI-compliant, but the default constraints aren't a part of ISO standard. Microsoft SQL Server provides system catalog views for getting information about SQL Server object metadata.
sys.default_constraints system catalog view used to getting the information about default constraints.
SELECT so.object_id TableName,
ss.name AS TableSchema,
cc.name AS Name,
cc.object_id AS ObjectID,
sc.name AS ColumnName,
cc.parent_column_id AS ColumnID,
cc.definition AS Defination,
CONVERT(BIT,
CASE cc.is_system_named
WHEN 1
THEN 1
ELSE 0
END) AS IsSystemNamed,
cc.create_date AS CreationDate,
cc.modify_date AS LastModifiednDate
FROM sys.default_constraints cc WITH (NOLOCK)
INNER JOIN sys.objects so WITH (NOLOCK) ON so.object_id = cc.parent_object_id
LEFT JOIN sys.schemas ss WITH (NOLOCK) ON ss.schema_id = so.schema_id
LEFT JOIN sys.columns sc WITH (NOLOCK) ON sc.column_id = cc.parent_column_id
AND sc.object_id = cc.parent_object_id
ORDER BY so.name,
cc.name;
A bit of a cleaner way to do this:
SELECT DC.[name]
FROM [sys].[default_constraints] AS DC
WHERE DC.[parent_object_id] = OBJECT_ID('[Schema].[TableName]')
If the target database has, say, over 1M objects, using sys.default_constraints can hit you with 90%+ taken on scanning sys.syscolpars followed by a Key Lookup for the dflt you likely don't care about. On my DB, it takes 1.129s to assemble just 4 rows from the 158 read of the residual I/O impaired 1.12MM rows actually scanned.
Changing to using the current sys.% tables/views, using #Tim's query, the same 4 constraints are acquired in 2ms. Hope someone finds this as useful as I found Tim's:
SELECT ConstraintName = sdc.name
, SchemaName = ssch.name
, TableName = stab.name
, ColumnName = scol.name
FROM sys.objects sdc
INNER JOIN sys.columns scol
ON scol.default_object_id = sdc.object_id
INNER JOIN sys.objects stab
ON stab.object_id = scol.object_id
INNER JOIN sys.schemas ssch
ON ssch.schema_id = stab.schema_id;