I am new to db world. I have to create a job that will drop the db snapshots and recreate it on daily basis. But I was wondering how can I validate once the snapshots is setup.
You can use SQLAgent to accomplish this: Creation & Deletion of Database Snapshot by SQL Agent Job
--Step 1 :-
DECLARE #CREATE_SS VARCHAR(MAX)
DECLARE #DT VARCHAR(100)
SET #DT = REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR,GETDATE(),120),’-‘,’_’),’ ‘,’_’),':’,’_’)
SET #CREATE_SS =
‘CREATE DATABASE TEST_’+#DT+’ ON
( NAME = TEST, FILENAME =
”C:\TEST_’+#DT+’.SS” )
AS SNAPSHOT OF TEST’
EXEC (#CREATE_SS)
--Step 2 :-
IF(SELECT COUNT(*) FROM SYS.DATABASES WHERE SOURCE_DATABASE_ID = DB_ID(‘TEST’))>1
BEGIN
DECLARE #DROP_SS VARCHAR(MAX)
DECLARE #SS_NAME VARCHAR(100)
SELECT TOP 1 #SS_NAME = NAME FROM SYS.DATABASES WHERE SOURCE_DATABASE_ID = DB_ID(‘TEST’)
ORDER BY CREATE_DATE ASC
SET #DROP_SS = ‘DROP DATABASE ‘+ #SS_NAME
EXEC (#DROP_SS)
END
For the validation part,you can use below query..
if exists(
SELECT * FROM sys.databases WHERE name = 'somename'
AND source_database_id IS NOT NULL)
begin
print 'database snapshot created'
end
Related
I have two databases in SQL Server. Let's say they are DB1 and DB2.
When the system starts, the current database is always DB1. BTW, I have to use DB2 for another table.
For the reason, I want to give a table name as a variable like #tablename and want to select a database name for the #tablename. Would it be possible to pull the database name associated with #tablename?
Also, I want to save the database name to a variable like #databasename to print it out.
When I tried to find a database name from the code below, I could get the database name of the table, ExampleTable, among DB1 and DB2.
EXEC sys.sp_msforeachdb
'SELECT ''?'' DatabaseName, name FROM [?].sys.Tables WHERE Name = ''ExampleTable'''
However, I can't go forward to process how to make a code using a variable #table instead of a fixed table name, ExampleTable.
I will use list of tables to input #tablename into the query one by one from the list.
DECLARE #table sysname = 'TableNames';
DECLARE #database_name sysname = 'dbo';
DECLARE #DatabaseName VARCHAR(50)
-- tbl_01 in dbo.DB1
-- tbl_02 in dbo.DB2
-- tbl_03 in dbo.DB1
-- tbl_04 in dbo.DB2
/*
I need the code block
(1) To input a table using #table
(2) To save the database name to a variable like #database_name
EXEC sys.sp_msforeachdb
'SELECT ''?'' DatabaseName, name FROM [?].sys.Tables WHERE Name ='+#table
*/
Please help me to create a script for my work.
The below code contains a set of tools you can use to do what you want to do. I expect your requirements may change a bit as you do this, so that's why I'm giving you the tools first.
These tools are written as simple checks - easy to understand and relatively quick. They currently just do a SELECT 'Yes' if the database exists/etc - but of course you can change that as needed.
DECLARE #DBName_1 nvarchar(100) = N'DB1';
DECLARE #DBName_2 nvarchar(100) = N'DB2';
DECLARE #TableName nvarchar(100) = N'MyTable';
DECLARE #TableNameToCheck nvarchar(200);
-- Is the current database 'DB1'?
IF DB_Name() = #DBName_1 SELECT 'Yes' ELSE SELECT 'No';
-- Check if the database 'DB2' exists
IF DB_ID(#DBName_2) IS NOT NULL SELECT 'Yes' ELSE SELECT 'No';
-- Check if table is in first database
SET #TableNameToCheck = QUOTENAME(#DBName_1) + N'.[dbo].' + QUOTENAME(#TableName);
IF OBJECT_ID(#TableNameToCheck, 'U') IS NOT NULL SELECT 'Yes' ELSE SELECT 'No';
-- Check if table is in second database (note it uses #DBName_2)
SET #TableNameToCheck = QUOTENAME(#DBName_2) + N'.[dbo].' + QUOTENAME(#TableName);
IF OBJECT_ID(#TableNameToCheck, 'U') IS NOT NULL SELECT 'Yes' ELSE SELECT 'No';
Note that you do not actually need the variable #TableNameToCheck - you can just construct it within the OBJECT_ID() function e.g., OBJECT_ID(#DBName_2 + N'.dbo.' + #TableName , 'U'). However, it can be useful to set it first to check/ensure it's correct, and it has infinitesimal impact on performance.
For your actual task (recording whether the table exists in DB1 or DB2) you can do the following
DECLARE #DBName_1 nvarchar(100) = N'DB1';
DECLARE #DBName_2 nvarchar(100) = N'DB2';
DECLARE #TableName nvarchar(100) = N'MyTable';
DECLARE #DatabaseWithTable nvarchar(100);
IF OBJECT_ID(QUOTENAME(#DBName_1) + N'.[dbo].' + QUOTENAME(#TableName), 'U') IS NOT NULL
BEGIN
SET #DatabaseWithTable = #DBName_1;
END
ELSE IF OBJECT_ID(QUOTENAME(#DBName_2) + N'.[dbo].' + QUOTENAME(#TableName), 'U') IS NOT NULL
BEGIN
SET #DatabaseWithTable = #DBName_2;
END
ELSE
BEGIN
SET #DatabaseWithTable = N'Not Found';
END;
SELECT #DatabaseWithTable;
Edit: Added QUOTENAME() as per suggestion/comment from #HABO
I've inherited a SQL 2008 dbase in which all of its objects are prefixed with the name of the developer as owner, i.e. ownername.sp_get_all_users.
I've restored the dbase onto SQL Server 2016 Express Edition.
There are several hundred dbase objects, is there a way to automate changing the object owners to dbo rather than manually editing each object?
I've tried the following but apparently you can no longer make ad-hoc changes to objects since SQL Server 2005?
SELECT * from sysobjects where uid = user_id('UseNAme')
declare #Return int
exec #Return = sp_configure 'allow updates', '1'
SELECT #Return as 'Returned Code'
GO
reconfigure WITH OVERRIDE
GO
DECLARE #Rows int, #Error int
BEGIN TRANSACTION
update sysobjects set uid = user_id('dbo') where uid = user_id('UseNAme')
SELECT #Error = ##Error, #Rows = ##RowCount
SELECT #Rows as '#Rows'
IF #Rows > 0
BEGIN
SELECT #Rows AS '#Rows'
COMMIT TRANSACTION
END
else
BEGIN
SELECT #Error AS 'Error #'
ROLLBACK TRANSACTION
END
exec sp_configure 'allow updates', '0'
reconfigure WITH OVERRIDE
go
Any help most appreciated.
You have to use Alter Schema...
ALTER SCHEMA oldschemaname TRANSFER dbo.Address;
To Automate use below
this will change all tables which have a schema other than system to dbo,note if you have two tables in different schema,they can't exist in same schema
select *,row_number() over (order by (select null)) as rownum
into #tables
from information_Schema.tables
where table_schema in (select name from sys.schemas
where name not in ('dbo','guest','INFORMATION_SCHEMA','sys') and principal_id <16384
)
now move
declare #min int,#max int
select #min=min(rownum),#max=max(rownum)
from #tables
declare #tblname varchar(255),#schemaname sysname
declare #sql varchar(max)
while #min<=#max
Begin
select #tblname=table_name,#schemaname=table_schema from
#tables where rownum=#min
set #sql='alter schema dbo transfer '+ #schemaname+'.'+#tblname
--print #sql
exec(#sql)
Set #min=#min+1
End
sp_change object owner as per documentation states..
This stored procedure only works with the objects available in MicrosoftSQL Server 2000. This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature. Use ALTER SCHEMA or ALTER AUTHORIZATION instead. sp_changeobjectowner changes both the schema and the owner. To preserve compatibility with earlier versions of SQL Server, this stored procedure will only change object owners when both the current owner and the new owner own schemas that have the same name as their database user names.
Use this sp_changeobjectowner
As explained here MSDN
For example: EXEC sp_changeobjectowner 'YourObject', 'dbo'
You can use this to alter schema statement for newer SQL Server DBS
declare #sql varchar(8000), #table varchar(1000), #oldschema varchar(1000), #newschema varchar(1000)
set #oldschema = 'dbo'
set #newschema = 'exe'
while exists(select * from sys.tables where schema_name(schema_id) = #oldschema)
begin
select #table = name from sys.tables
where object_id in(select min(object_id) from sys.tables where schema_name(schema_id) = #oldschema)
set #sql = 'alter schema ' + #newschema + ' transfer ' + #oldschema + '.' + #table
exec(#sql)
end
Your general idea of looping through the objects owned by the developer is a good idea (assuming you've tested the heck out of it). I'd suggest using the ALTER AUTHORIZATION command instead MSDN Doc
In addition to the advice above, the following changes the owner of SPs:
Declare #sql varchar(8000),
#table varchar(1000),
#oldschema varchar(1000),
#newschema varchar(1000)
set #oldschema = 'developername'
set #newschema = 'dbo'
while exists(select * from information_schema.routines where routine_type = 'PROCEDURE' and routine_schema = #oldschema )
begin
select #table = SPECIFIC_NAME from information_schema.routines
where SPECIFIC_NAME in(select SPECIFIC_NAME from information_schema.routines where routine_type = 'PROCEDURE' and routine_schema = #oldschema)
set #sql = 'alter schema ' + #newschema + ' transfer ' + #oldschema + '.' + #table
exec(#sql)
end
Is there a way to disable certian index DDL operation (create, drop and alter index) for a list of tables in MS SQL Server 2008 R2?
What I was trying to do is to create a DDL trigger that catch these events and roll them back, but it seems that all ddl trigers are after triggers and if table is very large this cause performance issues.
The trigger I am currently using is the following:
CREATE TRIGGER index_guard
ON DATABASE
FOR CREATE_INDEX, DROP_INDEX, ALTER_INDEX
AS
DECLARE #object_name NVARCHAR(50);
DECLARE #table_name NVARCHAR(50);
DECLARE #target_object_type NVARCHAR(20);
DECLARE #object_type NVARCHAR(20);
DECLARE #lookup_value NVARCHAR(100);
DECLARE #protected_indexes TABLE (Name NVARCHAR(50))
INSERT INTO #protected_indexes
SELECT Name FROM (VALUES ('TABLE1/IX_IdName'), ('TABLE2/IX_NameId')) AS tbl(Name)
SELECT #object_name = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','nvarchar(max)');
SELECT #table_name = EVENTDATA().value('(/EVENT_INSTANCE/TargetObjectName)[1]','nvarchar(max)');
SELECT #target_object_type = EVENTDATA().value('(/EVENT_INSTANCE/TargetObjectType)[1]','nvarchar(max)');
SELECT #object_type = EVENTDATA().value('(/EVENT_INSTANCE/ObjectType)[1]','nvarchar(max)');
IF #object_type = 'INDEX' AND #target_object_type = 'TABLE'
BEGIN
SET #lookup_value = #table_name + '/' + #object_name
IF EXISTS (SELECT 1 FROM #protected_indexes A WHERE A.Name = #lookup_value)
BEGIN
ROLLBACK
END
END
I'm quite new at SQL Server 2012, and I'm having a strange problem.
I've developed an AFTER UPDATE trigger on a table in my database. I created the trigger in our development environment which is an express edition of SQL Server 2012, no problem.
Now I have to create the same trigger in our production environment which is SQL Server 2012 Enterprise edition, and the creation script never stops executing, and the trigger is not created.
Any ideas on what I need to do to create the trigger?
The script :
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
alter TRIGGER [dbo].[til_aks_ved_betaling]
ON [dbo].[betalingsOplysningerbo]
AFTER UPDATE
AS
BEGIN
declare #snr uniqueidentifier
declare ##status varchar(1024)
SET NOCOUNT ON;
select
#snr = indmeldelse_snr
from
inserted
if UPDATE(betalingsDato)
begin
set ##status = 'Kalder med snr = ' + convert(varchar(38), #snr)
exec xp_logevent 60000, ##status , informational
exec overfoer_betalingsdato #snr
end
END
Try something like this....
ALTER TRIGGER [dbo].[til_aks_ved_betaling]
ON [dbo].[betalingsOplysningerbo]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
declare #snr VARCHAR(1000);
declare #status varchar(1024);
DECLARE #Temp TABLE (indmeldelse_snr uniqueidentifier , [Status] varchar(1024))
INSERT INTO #Temp (indmeldelse_snr , [Status])
SELECT i.indmeldelse_snr , i.[Status]
FROM inserted i INNER JOIN deleted d
ON i.Snr = d.Snr AND i.betalingsDato <> d.betalingsDato
WHILE EXISTS(SELECT * FROM #Temp)
BEGIN
SELECT TOP 1 #snr = 'Kalder med snr = ' + convert(varchar(38),indmeldelse_snr )
,#status = [Status]
FROM #Temp
exec xp_logevent 60000, #status , informational
exec overfoer_betalingsdato #snr
DELETE FROM #Temp WHERE indmeldelse_snr = #snr
END
END
2 things here, common for new people, an UPDATE is a DELETE and an INSERT so make sure you have both before you assume it is an update. Second, these special tables will return all the rows affect by a single sql call. For example, Update Table SET This = 'That' will update every record in the table leaving INSERTED with MANY records.
T-SQL to find if a Database is Subscribed on the Subscriber in Transactional Replication. I don't want to query Distribution for the details.
The following doesn't work.
SELECT is_subscribed FROM sys.databases
SELECT DATABASEPROPERTYEX('database', 'IsSubscribed')
So far this is the best way I found but I am not sure if this works in Non-Transactional Replication.
SELECT COALESCE(OBJECTPROPERTY(OBJECT_ID('dbo.MSreplication_objects'), 'IsMSShipped'),0) AS IsSubscribed
OR
SELECT name
FROM sys.databases
WHERE OBJECT_ID(name+'.dbo.MSreplication_objects') IS NOT NULL
The query above will work unless there are some databases that are not ONLINE, for example RESTORING then the query will fail. It's better to copy the list of available databases into temp table and then run the logic against it:
IF OBJECT_ID('tempdb..#db') IS NOT NULL DROP TABLE #db
SELECT name INTO #db FROM sys.databases WHERE state_desc = 'ONLINE'
SELECT name FROM #db WHERE OBJECT_ID(name+'.dbo.MSreplication_objects') IS NOT NULL
first you get Aaron Bertrand's sp_foreachdb replacement for sp_MSforeachdb
then you use it in the script below:
---------------------------------------------------------
-- get all info about subscribers in a server
-- marcello miorelli
-- 23-dec-2017
---------------------------------------------------------
IF object_id('TEMPDB..#RADHE_SP2') IS NOT NULL
DROP TABLE #RADHE_SP2
create table #RADHE_SP2 (
publisher sysname NOT NULL,
publisher_db sysname NOT NULL,
publication sysname NOT NULL,
replication_type int,
subscription_type int,
last_updated datetime,
subscriberd_db sysname,
update_mode int,
last_sync_status int,
last_sync_summary nvarchar(4000),
last_sync_time datetime)
declare #db_list NVARCHAR(MAX)
SELECT #db_list = STUFF((
SELECT ', ' + name
FROM sys.databases d
WHERE 1=1
and d.[state] = 0
FOR XML PATH(''), TYPE).value('.[1]', 'nvarchar(max)'), 1, 2, '')
--select #db_list
--exec sp_foreachdb #database_list = #db_list
-- ,#command='use ?; print db_name()'
EXEC sp_foreachdb
#database_list = #db_list,
#command=
'use ?;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
insert into #RADHE_SP2
exec sp_MSenumsubscriptions
'
SELECT * FROM #RADHE_SP2
that will give you something like this: