I have a large database that were used to archive tables before implementing structural change on it.
We had this database for years, I want to create a dynamic script to check today's date and drop any table in this database that were created 3 years or older.
Thanks
For MS SQL Below script may serve your purpose
select
'drop table [' + s.name +'].[' + t.name +']' , t.create_date
from
sys.tables t
inner join
sys.schemas s
on
s.schema_id = t.schema_id
where
create_date< DATEADD(year,-3, GETDATE())
and type='U'
Related
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 try to drop a column in SQL but I am getting this error:
The object 'DF__...'is dependent on column ...
I found a lot of solutions that need to drop the Constraint first, so I ran this and worked:
ALTER TABLE [dbo].[Configuration] DROP CONSTRAINT DF__SiteConfi__Na__2DFCAC08;
ALTER TABLE [dbo].[Configuration] DROP COLUMN NaFlag;
But I need this script to run on any server, so I don't want to mention the Constraint name as it may be different on any other servers. What is the best solution?
You can use some dynamic SQL to drop the default. If it's an isolated script to just drop the column, then it's easier, something like:
DECLARE #sqlDF NVARCHAR(MAX);
SELECT #sqlDF = 'ALTER TABLE {$tableName} DROP CONSTRAINT ' + QUOTENAME(OBJECT_NAME([default_object_id])) + ';'
FROM sys.columns
WHERE [object_id] = OBJECT_ID('{$tableName}') AND [name] in ({$columns}) AND [default_object_id] <> 0;
IF #sqlDF IS NOT NULL
EXEC(#sqlDF);
If you are working with a migrations tool, maybe you're gonna have to refactor this, so it doesn't try to redeclare the #sqlDF variable.
Here's a query to get you started:
with q as
(
select schema_name(t.schema_id) schema_name,
t.name table_name,
c.name column_name,
d.name default_name
from sys.tables t
join sys.columns c
on t.object_id = c.object_id
join sys.default_constraints d
on d.parent_object_id = t.object_id
and d.parent_column_id = c.column_id
)
select concat(
'alter table ',
quotename(schema_name),'.',quotename(table_name),
' drop constraint ', quotename(default_name) ) sql
from q
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.
Is there a way to create an XML schema from an existing database in SQL Server 2008, SQL Server Management Studio?
I have a DB with ~50 tables. I'm looking to create a "nice" diagram showing the relationship between those tables. Using another application called SQL Designer (https://code.google.com/p/wwwsqldesigner/) will give me the "nice" looking picture, but I don't know how to create the XML schema required.
I did a search across the forum (and MS) and couldn't quite find my answer. I could find tools which created a database, but I'm looking at the reverse... I need a pretty picture which shows the database in diagrammatic form. I thought if I could get my db structure into XML then SQL Designer will do the rest for me.
Thanks for your assistance.
Nick
If you only need the xml schema of tables query them with this:
select top 0 * FROM daTable FOR XML AUTO,XMLSCHEMA
If you need the table names and columns in order to create a representation of your database and how tables are connected you can use something like this:
SELECT
s.name as '#Schema'
,t.name as '#Name'
,t.object_id as '#Id'
,(
SELECT c.name as '#Name'
,c.column_id as '#Id'
,IIF(ic.object_id IS NOT NULL,1,0) as '#IsPrimaryKey'
,fkc.referenced_object_id as '#ColumnReferencesTableId'
,fkc.referenced_column_id as '#ColumnReferencesTableColumnId'
FROM sys.columns as c
LEFT OUTER JOIN sys.index_columns as ic
ON c.object_id = ic.object_id
AND c.column_id = ic.column_id
AND ic.index_id = 1
LEFT OUTER JOIN sys.foreign_key_columns as fkc
ON c.object_id = fkc.parent_object_id
AND c.column_id = fkc.parent_column_id
WHERE c.object_id = t.object_id
FOR XML PATH ('Column'),TYPE
)
FROM sys.schemas as s
INNER JOIN sys.tables as t
ON s.schema_id = t.schema_id
FOR XML PATH('Table'),ROOT('Tables')
Let your application use the ColumnReferencesTableId and ColumnReferencesTableColumnId to get table relations. You could also further join back to columns and tables which are referenced if you prefer writing their names out but I thought their Ids would suffice.
Combined with a cursor running through INFORMATION_SCHEMA or sysobjects, the following should help you:
SELECT * FROM [MyTable] FOR XML AUTO, XMLSCHEMA
I'm uncertain as to whether you can simply apply this to a whole database, or what postprocessing effort would be required to combine all the various table schemas, but it's something to work with.
Try this (a variation of this answer):
DECLARE #listStr VARCHAR(MAX)
SELECT #listStr = COALESCE(#listStr+',' ,'') + TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
EXEC('
DECLARE #schema xml
SET #schema = (SELECT TOP 0 * FROM ' +
#listStr +
' FOR XML AUTO, ELEMENTS, XMLSCHEMA(''DbSchema''))
SELECT #schema
');
Replace the line:
,**IIF**(ic.object_id IS NOT NULL,1,0) as '#IsPrimaryKey'
With this:
,CASE WHEN ic.object_id IS NOT NULL THEN 1 ELSE 0 END AS '#IsPrimaryKey'
for MS SQL server versions not allowing the IIF function.
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' + '%'