The system beep is unaffected by windows volume control / sound card settings. If you're working late@ night and dont want to upset the missus, here is how to disable it >
Go to the dos prompt (START > RUN > type 'CMD' {Enter]
Run these 2 commands >
net stop beep [ENTER]
sc config beep start= disabled [ENTER]
Personally, i pasted those two command lines into a batch file and ran it on my machines (physical and virtual).
Thursday, 29 June 2006
Monday, 26 June 2006
LDAP Error
Recording this as a memory jogger in case I see it again...
" Msg 7346, Level 16, State 2, Line 1
Cannot get the data of the row from the OLE DB provider "ADSDSOObject" for linked server "linkedservername".
Could not convert the data value due to reasons other than sign mismatch or overflow. "
Was retrieving data from Active Directory via a linked server in SQL.
Bottom line is that you cannot use OPENQUERY to get multivalued attributes or columns containing date information from AD.
" Msg 7346, Level 16, State 2, Line 1
Cannot get the data of the row from the OLE DB provider "ADSDSOObject" for linked server "linkedservername".
Could not convert the data value due to reasons other than sign mismatch or overflow. "
Was retrieving data from Active Directory via a linked server in SQL.
Bottom line is that you cannot use OPENQUERY to get multivalued attributes or columns containing date information from AD.
Sunday, 25 June 2006
Querying Active Directory Group membership from SQL
Querying Active Directory Group membership from SQL
Inspired from (& based on) code @ http://codebetter.com/blogs/brendan.tompkins/archive/2003/12/19/4746.aspx
This code looks at an LDAP v2 source eg; Windows 2000 and fetches users, groups and membership information.
You need to set up a linked server called 'ADSI' to get this to function.
Setting up the linked server -
The code itself -
Inspired from (& based on) code @ http://codebetter.com/blogs/brendan.tompkins/archive/2003/12/19/4746.aspx
This code looks at an LDAP v2 source eg; Windows 2000 and fetches users, groups and membership information.
You need to set up a linked server called 'ADSI' to get this to function.
Setting up the linked server -
EXEC master.dbo.sp_addlinkedserver @server = N'ADSI', @srvproduct=N'Active Directory Services 2.5', @provider=N'ADSDSOObject', @datasrc=N'adsdatasource' GO EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N'ADSI',@useself=N'False',@locallogin=NULL,@rmtuser=N'domain\user',@rmtpassword='########' GO EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'collation compatible', @optvalue=N'false' GO EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'data access', @optvalue=N'true' GO EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'dist', @optvalue=N'false' GO EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'pub', @optvalue=N'false' GO EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'rpc', @optvalue=N'false' GO EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'rpc out', @optvalue=N'false' GO EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'sub', @optvalue=N'false' GO EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'connect timeout', @optvalue=N'0' GO EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'collation name', @optvalue=null GO EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'lazy schema validation', @optvalue=N'false' GO EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'query timeout', @optvalue=N'0' GO EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'use remote collation', @optvalue=N'true'
The code itself -
-- Configure AD Domain to search DECLARE @strDC NVARCHAR(100) SET @strDC = 'dc=domain,dc=co,dc=uk' -- Declare Variables DECLARE @chvAlphaChars VARCHAR(60), @chvSearch VARCHAR(10), @chvSearchLevel1 VARCHAR(1), @chvSearchLevel2 VARCHAR(1), @chvSearchLevel3 VARCHAR(1), @intcountLevel1 INT, @intcountLevel2 INT, @intcountLevel3 INT, @intRowCount INT, @strSQL NVARCHAR(4000), @strADSISQL NVARCHAR(4000), @Login VARBINARY(85), @CN VARCHAR(512), @CT INT, @ADRoot VARCHAR(255) -- Declare temp tables IF EXISTS (SELECT * FROM TEMPDB.DBO.SYSOBJECTS WHERE ID = OBJECT_ID('tempdb.dbo.#LDAP_AD_V2_Users')) DROP TABLE #LDAP_AD_V2_USERS CREATE TABLE [DBO].[#LDAP_AD_V2_USERS] ( [ROW_ID] [INT] IDENTITY ( 1,1 ) NOT NULL, [SID] [VARBINARY](85) NULL, [SAMACCOUNTNAME] [NVARCHAR](256) NULL, [CN] [NVARCHAR](256) NULL, [SN] [NVARCHAR](256) NULL, [DISPLAYNAME] [NVARCHAR](256) NULL, [GIVENNAME] [NVARCHAR](256) NULL, [TELEPHONENUMBER] [NVARCHAR](256) NULL, [ADSPATH] [NVARCHAR](256) NULL, [HOMEDIRECTORY] [NVARCHAR](256) NULL, [MAIL] [NVARCHAR](256) NULL, [MEMBEROF] [NVARCHAR](256) NULL, [PRIMARYGROUPID] [INT], [CREATETIMESTAMP] DATETIME) ON [PRIMARY] IF EXISTS (SELECT * FROM TEMPDB.DBO.SYSOBJECTS WHERE ID = OBJECT_ID('tempdb.dbo.#LDAP_AD_V2_Groups')) DROP TABLE #LDAP_AD_V2_GROUPS CREATE TABLE [DBO].[#LDAP_AD_V2_GROUPS] ( [ID] [INT] IDENTITY ( 1,1 ) NOT NULL, [LOGIN] [VARCHAR](512) NULL, [EMAIL] [VARCHAR](255) NULL, [ACCTNAME] [VARCHAR](512) NULL, [DISTNAME] [VARCHAR](512) NULL, [CREATEDDATE] [DATETIME] NULL, [CHANGEDDATE] [DATETIME] NULL, [MGR] [VARCHAR](512) NULL, [SID] [VARBINARY](85) NULL) ON [PRIMARY] IF EXISTS (SELECT * FROM TEMPDB.DBO.SYSOBJECTS WHERE ID = OBJECT_ID('tempdb.dbo.#LDAP_AD_V2_UserGroups')) DROP TABLE #LDAP_AD_V2_USERGROUPS CREATE TABLE [DBO].[#LDAP_AD_V2_USERGROUPS] ( [USERLOGIN] [VARBINARY](85) NOT NULL, [GROUPLOGIN] [VARBINARY](85) NULL) ON [PRIMARY] -- POPULATION OF USERS -- Search letters to cycle through -- any chars, but the first char must be a space SET @chvAlphaChars = ' ABCDEFGHIJKLMNOPQRSTUVWXYZ.-_`0123456789' SET NOCOUNT ON -- start on non space char SET @intcountLevel1 = 2 -- first level loop WHILE @intcountLevel1 <= LEN(@chvAlphaChars) BEGIN -- get first level char SET @chvSearchLevel1 = SUBSTRING(@chvAlphaChars,@intcountLevel1,1) -- reset start on space SET @intcountLevel2 = 1 -- second level loop WHILE @intcountLevel2 <= LEN(@chvAlphaChars) BEGIN -- reset start on space SET @intcountLevel3 = 1 -- third level loop WHILE @intcountLevel3 <= LEN(@chvAlphaChars) BEGIN -- setup the string to search for. By using the trim function we can form each level depending on no records -- eg A 99, B 1000 > BA 9, BB 20 etc -- trim the spaces forming just A, B, C ; AA, AB for search etc SET @chvSearchLevel1 = SUBSTRING(@chvAlphaChars,@intcountLevel1,1) SET @chvSearchLevel2 = RTRIM(SUBSTRING(@chvAlphaChars,@intcountLevel2,1)) SET @chvSearchLevel3 = RTRIM(SUBSTRING(@chvAlphaChars,@intcountLevel3,1)) SET @chvSearch = @chvSearchLevel1 + @chvSearchLevel2 + @chvSearchLevel3 SET @strADSISQL = 'select objectSid,cn,sn,displayName, sAMAccountName, givenName, telephoneNumber, adspath, homedirectory, mail, primarygroupid, createTimeStamp ' + CHAR(13) + 'from ''''LDAP://' + @strDC + ''''' ' + CHAR(13) + 'where objectCategory = ''''Person'''' ' + CHAR(13) + 'and objectClass = ''''user'''' ' + CHAR(13) + 'and sAMAccountName = ''''' + @chvSearch + '*'''' ' SET @strSQL = 'insert into #LDAP_AD_V2_Users (sid,cn,sn,displayName, sAMAccountName, givenName, telephoneNumber, adspath, homedirectory, mail, primarygroupid, createTimeStamp) ' + CHAR(13) + 'select objectSid,cn,sn,displayName, sAMAccountName, givenName, telephoneNumber, adspath, homedirectory, mail, primarygroupid, createTimeStamp ' + CHAR(13) + 'from openquery(ADSI,''' + @strADSISQL + ''' ) ' + CHAR(13) + 'order by sAMAccountName' EXEC SP_EXECUTESQL @strSQL SET @intRowCount = @@ROWCOUNT -- prints what string is being searched for : no of inserts -- PRINT @chvSearch + ' : ' + CONVERT(VARCHAR,@intRowCount) -- if searched on @chvSearchLevel1 and under 1000 then everything is fine so skip search2 to next search1 eg A > B IF @intRowCount < 1000 AND @chvSearchLevel2 = '' SET @intcountLevel2 = @intcountLevel2 + 100 -- if searched on @chvSearchLevel2 and under 1000 then everything is fine so skip to next search2 eg AA > AB IF @intRowCount < 1000 AND @chvSearchLevel3 = '' SET @intcountLevel3 = @intcountLevel3 + 100 -- else over 1000 so increment third level SET @intcountLevel3 = @intcountLevel3 + 1 END -- increment next second level char SET @intcountLevel2 = @intcountLevel2 + 1 END -- increment next first level char SET @intcountLevel1 = @intcountLevel1 + 1 END -- POPULATION OF GROUPS SET @strADSISQL = 'select objectSid, managedBy, whenChanged, whenCreated, distinguishedName, name, samAccountName, mail ' + CHAR(13) + 'FROM ''''LDAP://' + @strDC + ''''' ' + CHAR(13) + 'WHERE objectCategory = ''''Group'''' ' SET @strSQL = 'insert into #LDAP_AD_V2_Groups (sid,mgr,changeddate,createddate,distname,acctname,email,login) ' + CHAR(13) + 'select objectSid,managedBy,whenChanged,whenCreated,distinguishedName,name,mail,samAccountName ' + CHAR(13) + 'from openquery(ADSI,''' + @strADSISQL + ''' ) ' + CHAR(13) + 'order by sAMAccountName' -- PRINT @strSQL EXEC SP_EXECUTESQL @strSQL -- POPULATION OF USER > GROUPS RELATIONSHIP TABLE IF EXISTS (SELECT * FROM TEMPDB.DBO.SYSOBJECTS WHERE ID = OBJECT_ID('tempdb.dbo.#CT')) DROP TABLE #CT -- Create a temporary table to hold AD user SID values CREATE TABLE #CT (CT VARBINARY(85)) -- Declare and open a cursor to step through the list of Active Directory groups DECLARE CURGROUPS CURSOR FOR SELECT SID, DISTNAME FROM #LDAP_AD_V2_GROUPS ORDER BY LOGIN OPEN CURGROUPS FETCH NEXT FROM CURGROUPS INTO @Login, @CN WHILE @@FETCH_STATUS = 0 BEGIN -- Empty the temp table TRUNCATE TABLE #CT -- Build a SQL statement to insert the SID values directly from the linked server into the temp table SET @strsql = 'INSERT #CT SELECT * FROM OPENQUERY ( ADSI, ''SELECT objectSid FROM ''''LDAP://' + @strDC + ''''' WHERE objectCategory = ''''User'''' AND memberof=''''' + REPLACE(@CN,'''','''''''''') + ''''''')' EXEC( @strsql) -- Select the number of records inserted. If this value is less than 1000 then there is no need -- to execute the OLE calls, and we simply copy the values into the correlation table. SELECT @CT = COUNT(* ) FROM #CT --PRINT @ct --PRINT @strsql IF @CT <> 0 BEGIN INSERT #LDAP_AD_V2_USERGROUPS (USERLOGIN, GROUPLOGIN) SELECT CT, @Login FROM #CT WHERE CT IS NOT NULL END FETCH NEXT FROM CURGROUPS INTO @Login, @CN END CURSORERROR: CLOSE CURGROUPS DEALLOCATE CURGROUPS DROP TABLE #CT /* -- Individual SQL Statements to see users, groups & relationships select * from #LDAP_AD_V2_Users select * from #LDAP_AD_V2_Groups select * from #LDAP_AD_V2_UserGroups */ -- Final Query to tie together the 3 tables and produce a report of group membership SELECT #LDAP_AD_V2_GROUPS.ACCTNAME AS GROUPNAME, #LDAP_AD_V2_USERS.SAMACCOUNTNAME AS USERACCOUNT FROM #LDAP_AD_V2_USERGROUPS INNER JOIN #LDAP_AD_V2_USERS ON #LDAP_AD_V2_USERGROUPS.USERLOGIN = #LDAP_AD_V2_USERS.SID INNER JOIN #LDAP_AD_V2_GROUPS ON #LDAP_AD_V2_USERGROUPS.GROUPLOGIN = #LDAP_AD_V2_GROUPS.SID ORDER BY #LDAP_AD_V2_GROUPS.ACCTNAME, #LDAP_AD_V2_USERS.SAMACCOUNTNAME
Friday, 23 June 2006
SQL 101 : Date Formatting
Casting a value as DateTime validates it -
When language is set to us_english, date format of 'mdy' expects the month to be provided before the day.
When language is set to british, date format of 'dmy' expects the day to be provided before the month.
In both of these cases, SQL correctly interprets the year, whether at the start or end of the string.
The failures generate -
Msg 242, Level 16, State 3, Line 7
The conversion of a char data type to a datetime data type resulted in an out-of-range datetime value.
Using set dateformat to override the language setting -
Best Practice is to use a language neutral date format -
More on language neutral date formats here - http://www.karaszi.com/SQLServer/info_datetime.asp
2 ways to get the current time & date -
-- SQL DateTime Validation SELECT CAST('2006-03-31' AS datetime) -- Succeeds, 31 days in March SELECT CAST('2006-04-31' AS datetime) -- Fails, only 30 days in April SELECT CAST('2006-02-29' AS datetime) -- Fails, No 29th day in Feb 2006 SELECT CAST('2004-02-29' AS datetime) -- Succeeds, was a leap year SELECT CAST('2002-02-29' AS datetime) -- Fails, No 29th day in Feb 2002 SELECT CAST('2000-02-29' AS datetime) -- Succeeds, was a leap year
When language is set to us_english, date format of 'mdy' expects the month to be provided before the day.
SET LANGUAGE us_english -- Changed language setting to us_english. SELECT CAST('2006-03-31' AS datetime) -- works SELECT CAST('03-31-2006' AS datetime) -- works SELECT CAST('31-03-2006' AS datetime) -- fails
When language is set to british, date format of 'dmy' expects the day to be provided before the month.
SET LANGUAGE british -- Changed language setting to British. SELECT CAST('2006-03-31' AS datetime) -- fails SELECT CAST('2006-31-03' AS datetime) -- works SELECT CAST('31-03-2006' AS datetime) -- works
In both of these cases, SQL correctly interprets the year, whether at the start or end of the string.
The failures generate -
Msg 242, Level 16, State 3, Line 7
The conversion of a char data type to a datetime data type resulted in an out-of-range datetime value.
Using set dateformat to override the language setting -
SET DATEFORMAT 'dmy' -- example SET LANGUAGE us_english -- Changed language setting to us_english. SET DATEFORMAT 'dmy' SELECT CAST('31-03-2006' AS datetime) -- now succeeds.
Best Practice is to use a language neutral date format -
-- ISO 8601 format doesnt care about language > SELECT CAST('2006-03-31T00:00:00' AS datetime) -- Neither does removing the '-' SELECT CAST('20060331' AS datetime)
More on language neutral date formats here - http://www.karaszi.com/SQLServer/info_datetime.asp
2 ways to get the current time & date -
SELECT CURRENT_TIMESTAMP SELECT getdate()
Tuesday, 20 June 2006
FTP Server : Filezilla
I originally needed a ftp server for testing ftp functionality in an application. Filezilla Server was recommended to me as quick, easy and most importantly FREE!
Download it here > http://sourceforge.net/projects/filezilla/
They also do a free FTP client hence I'm ditching SmartFTP for Filezilla >
Yes, I know you can ftp from within I.E and the OS, but this is the real world, where usability and reliability rule :)
Download it here > http://sourceforge.net/projects/filezilla/
They also do a free FTP client hence I'm ditching SmartFTP for Filezilla >
Yes, I know you can ftp from within I.E and the OS, but this is the real world, where usability and reliability rule :)
Monday, 19 June 2006
SQL : Make all columns NULLable
SELECT 'alter table ' + TABLE_NAME + ' alter column ' + COLUMN_NAME + ' ' + data_type + '(' + CAST(CHARACTER_MAXIMUM_LENGTH as VARCHAR(5)) + ') NULL' FROM INFORMATION_SCHEMA.COLUMNS WHERE IS_NULLABLE = 'NO' AND DATA_TYPE IN ('VARCHAR','CHAR')
Saturday, 17 June 2006
Dynamic SQL - Passing a parameter using sp_execute
/* Dynamic SQL : Passing a parameter to sp_execute Example uses AdventureWorks db */ exec sp_executesql N'SELECT e.[EmployeeID] ,c.[Title] ,c.[FirstName] ,c.[MiddleName] ,c.[LastName] ,c.[Suffix] ,e.[Title] AS [JobTitle] ,c.[Phone] ,c.[EmailAddress] ,c.[EmailPromotion] ,a.[AddressLine1] ,a.[AddressLine2] ,a.[City] ,sp.[Name] AS [StateProvinceName] ,a.[PostalCode] ,cr.[Name] AS [CountryRegionName] ,c.[AdditionalContactInfo] FROM [HumanResources].[Employee] e INNER JOIN [Person].[Contact] c ON c.[ContactID] = e.[ContactID] INNER JOIN [HumanResources].[EmployeeAddress] ea ON e.[EmployeeID] = ea.[EmployeeID] INNER JOIN [Person].[Address] a ON ea.[AddressID] = a.[AddressID] INNER JOIN [Person].[StateProvince] sp ON sp.[StateProvinceID] = a.[StateProvinceID] INNER JOIN [Person].[CountryRegion] cr ON cr.[CountryRegionCode] = sp.[CountryRegionCode] AND cr.[Name] = @Region',N'@Region varchar(20)','Germany'
Thursday, 15 June 2006
Send email from TSQL
SQL 2005 Database Mail, Sending email from TSQL -
This script assumes you have set up database mail with an account name of 'SQL Administrator' and provided valid SMTP details.
This script assumes you have set up database mail with an account name of 'SQL Administrator' and provided valid SMTP details.
-- declare variables DECLARE @chvFrom VARCHAR(255) DECLARE @chvTo VARCHAR(255) DECLARE @chvSubject VARCHAR(255) DECLARE @chvBody VARCHAR(8000) -- set values SET @chvFrom = 'SQLAdmin@mydomain.net' SET @chvTo = 'recipient@mydomain.net' SET @chvSubject = 'Test email from ' + @@SERVERNAME SET @chvBody = 'test body text' -- send the mail EXEC msdb.dbo.sp_send_dbmail @profile_name='SQL Administrator', @recipients=@chvTo, @body=@chvBody,@subject=@chvSubject, @importance='High'
Wednesday, 7 June 2006
ISO Image Tools
Not so long ago, I was swimming in discs. Software and OS discs each on CD, neatly filed away in multiple folders. I was beginning to rival an MSDN subscription in terms of volume when I had a sort out, binned anything that had been superceeded and consolidating the rest to DVD.
The latest updates and installers are taking the form of ISO files i.e. image files of installation media. These are the FREE tools I rate for dealing with ISO files.
Daemon Tools - Emulates an optical drive so you can use an image without burning to disc.
DoISO - Create ISO files from a given directory.
ImgBurn - Burns ISOs to disc and extracts images from discs. Especially good with 'difficult' discs. Used to be known as DVD Decrypter.
The latest updates and installers are taking the form of ISO files i.e. image files of installation media. These are the FREE tools I rate for dealing with ISO files.
Daemon Tools - Emulates an optical drive so you can use an image without burning to disc.
UPDATE May 2010
Virtual Clonedrive is better and doesn't prompt you to install lots of add-ins / extras.DoISO - Create ISO files from a given directory.
ImgBurn - Burns ISOs to disc and extracts images from discs. Especially good with 'difficult' discs. Used to be known as DVD Decrypter.
Sunday, 4 June 2006
SQL 2005+ - TRY CATCH Error detection
Prior to SQL 2005, errors in TSQL code had to be tested for and captured by @@ERROR.
SQL 2005 implements the TRY CATCH syntax in the same way as javascript, c++ and subsequently the .NET languages.
For example, using AdventureWorks, I purposely attempt to delete a record I shouldnt, and receive an error -
Msg 547, Level 16, State 0, Line 2
The DELETE statement conflicted with the REFERENCE constraint "FK_EmployeeAddress_Address_AddressID". The conflict occurred in database "AdventureWorks", table "HumanResources.EmployeeAddress", column 'AddressID'.
The statement has been terminated.
@@ERROR only contains the error in the very next statement after the error, hence to both examine & display the value I have to assign it to a local variable -
TSQL Programming to catch the error -
Msg 547, Level 16, State 0, Line 2
The DELETE statement conflicted with the REFERENCE constraint "FK_EmployeeAddress_Address_AddressID". The conflict occurred in database "AdventureWorks", table "HumanResources.EmployeeAddress", column 'AddressID'.
The statement has been terminated.
Error 547 : Could not Delete record
Note : both the SQL Error and my message are returned.
Using TRY/CATCH however, the error can be caught and the script continues -
Much tidier, only my error message is returned -
Error 547 : Could not Delete record
SQL 2005 implements the TRY CATCH syntax in the same way as javascript, c++ and subsequently the .NET languages.
For example, using AdventureWorks, I purposely attempt to delete a record I shouldnt, and receive an error -
DELETE Person.Address WHERE AddressID = 1
Msg 547, Level 16, State 0, Line 2
The DELETE statement conflicted with the REFERENCE constraint "FK_EmployeeAddress_Address_AddressID". The conflict occurred in database "AdventureWorks", table "HumanResources.EmployeeAddress", column 'AddressID'.
The statement has been terminated.
@@ERROR only contains the error in the very next statement after the error, hence to both examine & display the value I have to assign it to a local variable -
TSQL Programming to catch the error -
DECLARE @ErrorResult INTEGER DELETE Person.Address WHERE AddressID = 1 SET @ErrorResult = @@ERROR IF @ErrorResult <>0 BEGIN PRINT 'Error ' + CAST(@ErrorResult AS VARCHAR(10)) + ' : Could not Delete record' END
Msg 547, Level 16, State 0, Line 2
The DELETE statement conflicted with the REFERENCE constraint "FK_EmployeeAddress_Address_AddressID". The conflict occurred in database "AdventureWorks", table "HumanResources.EmployeeAddress", column 'AddressID'.
The statement has been terminated.
Error 547 : Could not Delete record
Note : both the SQL Error and my message are returned.
Using TRY/CATCH however, the error can be caught and the script continues -
BEGIN TRY -- Attempt delete of referenced record. DELETE Person.Address WHERE AddressID = 1 END TRY BEGIN CATCH -- Do alternate action. PRINT 'Could not Delete record' END CATCH
Much tidier, only my error message is returned -
Error 547 : Could not Delete record
Friday, 2 June 2006
Accessing AD Users & Computers on a Member Server
Launch Microsoft Management Console
Start > Run > MMC [enter]
File > Add / Remove Snap-In
Click 'Add' to see available snap-ins.
Select 'Active Directory Users and Computers'
Click the 'Add', then 'Close' and finally 'OK'.
The functionality available will obviously depend on who you are logged in as.
Start > Run > MMC [enter]
File > Add / Remove Snap-In
Click 'Add' to see available snap-ins.
Select 'Active Directory Users and Computers'
Click the 'Add', then 'Close' and finally 'OK'.
The functionality available will obviously depend on who you are logged in as.
Thursday, 1 June 2006
Removing Database Backup History
The msdb database stores (amongst other things) the history of backups performed on the sql instance.
Once a backup has been archived, i.e. moved away from the location it was originally written to, there is no need to keep the record of the backup. Infact, these records build up, increasing the size of the msdb database (quickly if frequent transaction log backups are performed).
To see the date range of backup history you have, us this query -
Once a backup has been archived, i.e. moved away from the location it was originally written to, there is no need to keep the record of the backup. Infact, these records build up, increasing the size of the msdb database (quickly if frequent transaction log backups are performed).
To see the date range of backup history you have, us this query -
use msdb SELECT a.name , MIN(b.backup_finish_date) EarliestSuccessfulBackup , MAX(b.backup_finish_date) LatestSuccessfulBackup FROM master..sysdatabases a LEFT OUTER JOIN msdb..backupset b ON a.name = b.database_name GROUP BY a.name ORDER BY a.nameTo prevent this occuring, use system stored procedure sp_delete_backuphistory and pass it the date of the oldest record you want to keep.
use msdb go exec sp_delete_backuphistory '1/1/2006'If a database is removed altogether, zap it's backup history like this -
exec msdb.dbo.sp_delete_database_backuphistory 'Adventureworks'If backups are archived regularly, schedule a job to remove excess history records, like this -
-- Calculate date to be used when removing records, -- This example deletes records over a month old. DECLARE @dtOldest_date DATETIME SET @dtOldest_date = dateadd(month, -1, getdate()) EXEC msdb..sp_delete_backuphistory @dtOldest_dateNB :SQL 2005+ addresses this by providing cleanup tasks in the Maintainence Plans (if you use them).
Subscribe to:
Posts (Atom)