Archive for the ‘SQL’ Category

list all logins of a server

July 14, 2009

I’ve found some tremendous resources for administrative sql scripts:
in general:
http://vyaskn.tripod.com/generate_scripts_repetitive_sql_tasks.htm
for the one I’m posting about: http://demiliani.com/blog/archive/2005/05/13/2449.aspx

But , you may ask, why should you get excited about some complicated sql script that generates other sql script that you must copy past and execute? Well, I have a server where someone created the SA userid, and it’s probably been there forever, and I’d like to get rid of it, but how do I know which databases it’s being used for?

put all the logins into a table:
1)
use master
select
'insert into loginstemp select ''' + name + ''' as DBName , name as Login from ' + name + '.sys.sysusers where islogin=1 '
as 'CopyAndExecute'
from master.dbo.sysdatabases

2) create temp table
use MyWriteTable

drop table loginstemp

create table loginstemp (DBName varchar(50), [Login] varchar(50) )

3) copy and execute the generated sql

use MyWriteTable

insert into loginstemp select 'ATable' as DBName , name as Login from ATable.sys.sysusers where islogin=1
insert into loginstemp select 'MyWriteTable' as DBName , name as Login from MyWriteTable.sys.sysusers where islogin=1
etc.

4) view temp table
use MyWriteTable
select * from loginstemp

size of all tables in a database

July 13, 2009

purpose – what if some tables are growing a lot more than you expected? wouldn’t it be handy to have a snapshot of how large all your tables are?


-- replace DB2Data for your own database
use db2data

if exists (select [id] from tempdb..sysobjects where [id] = OBJECT_ID ('tempdb..#TempCountRecords '))
DROP TABLE #TempCountRecords

CREATE TABLE #TempCountRecords (
[Table_Name] varchar(50),
[CountRecords] int
)

declare @SQLcommand varchar(200)

declare @TableName varchar(50)
declare @TableSchema varchar(50)
DECLARE c_db CURSOR FOR SELECT table_name, table_schema from information_schema.tables where table_type='base table'

OPEN c_db
FETCH NEXT FROM c_db INTO @TableName, @TableSchema
WHILE @@FETCH_STATUS = 0
begin

set @TableName = '['+@tableschema + '].[' + @tableName + ']'

set @SQLCommand = ' select ''QQQ'' as [Table_Name] , count(*) as [CountRecords] from QQQ '
set @SQLcommand = replace( @SQLcommand , 'QQQ' , @TableName )
print @SQLcommand

-- insert and execute all in one statement - refer to ms_Script.sql in the Status_DBQueries
insert #TempCountRecords
EXECUTE (@SQLcommand)

FETCH NEXT FROM c_db INTO @TableName, @tableschema

end
DEALLOCATE c_db

select * from #TempCountRecords order by CountRecords desc
drop table #TempCountRecords

search all tables for a string

June 5, 2009

I needed to search the ‘description’ field of every table in my database for a string.
To do that, I generated a column of search commands.
Then I copied those search commands into a new query window in sql server enterprise manager and executed them. I could see which tables contained the string I was looking for.

Here is the sql to generate the column of commands. A trick is to concatenate the literal single quote string.

**********************************************
SEARCH all tables , ALL COLUMNS NAMED ‘DESCRIPTION’ FOR RECORDS CONTAINING A KEY WORD
*******************

select (‘Select ‘ + char(39) + table_name + char(39) + ‘ as TableName ,* from ‘ + table_name + ‘ where [description] like ‘ + char(39) + ‘%Back Flow%’ + char(39) + ‘ ‘ ) as copyandexecute , column_name from INFORMATION_SCHEMA.columns
where column_name = ‘Description’
order by column_name

search all stored procedures for a string

June 5, 2009

Search all stored procedures that contain some text

select specific_name , Routine_Definition from INFORMATION_SCHEMA.ROUTINES
where Routine_Definition like ‘%tblRatingSectionItemAttribute%’
– runs into a limit on string length

THIS WORKED
SELECT OBJECT_NAME(id) , [text]
FROM syscomments
WHERE [text] LIKE ‘%Back Flow%’
AND OBJECTPROPERTY(id, ‘IsProcedure’) = 1
GROUP BY OBJECT_NAME(id) , [text]

count all recently updated time-sensitive records in an entire database

April 8, 2009


-- purpose - see if this database is being updated
-- use a set of queries on datetime fields.
-- Make the queries dynamic, and pass in the table and column names.
-- collate results into a temp table and then display all together
declare @t_name varchar(50)
declare @c_name varchar(50)
declare @query_base varchar(250)
set @query_base = 'select {QQQTABLE} as [TableName], count(*) as CountRecentUpdates from QQQTABLE where

QQQCOLUMN > dateadd(d,-1,getdate() )'
declare @query varchar(500)
declare @TempTableInsert varchar(80)
set @TempTableInsert = ' insert into #MyTempTable ([TableName] , [CountRecentUpdates] ) '

CREATE TABLE #MyTempTable ([TableName] varchar(50), [CountRecentUpdates] varchar(50) )

declare ci cursor for
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE (DATA_TYPE = 'datetime') AND (NOT (COLUMN_DEFAULT IS NULL))

open ci

fetch next from ci into
@t_name,
@c_name

WHILE @@FETCH_STATUS = 0

BEGIN

--print @t_name + ' ' + @c_name

set @query = replace(@query_base,'QQQTABLE', @t_name)
set @query = replace(@query ,'QQQCOLUMN', @c_name)
set @query = replace(@query ,'{' , char(39) )
set @query = replace(@query ,'}' , char(39) )
set @query = @TempTableInsert + @query
--print @query
EXECUTE(@query)
-- *************************************************************
-- RE-LOAD THE CURSOR
fetch next from ci into
@t_name,
@c_name

end
close ci
deallocate ci

select * from #MyTempTable
drop table #MyTempTable

/*
reference query
SELECT TABLE_NAME, COLUMN_NAME, IS_NULLABLE, DATA_TYPE, COLUMN_DEFAULT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE (DATA_TYPE = 'datetime') AND (NOT (COLUMN_DEFAULT IS NULL))

*/

The output looks like this:

TableName CountRecentUpdates
Exceptions 0
Results 232
Links 0
Results_Unstructured 0
Debugging 3290
AppStatus 0
OutageLog 0
Events 1008
StatusLog 0
Queries 3

recursive stored procedure

March 11, 2009

The business purpose of this stored procedure is to permit a project to contain a sub-project. Because each sub-project could again contain other projects, it looked like I could potentiall get infinite loops in my logic. Therefore I wanted to prevent loop backs in my chains of projects.

The recursive stored procedure was able to walk up the chain of containing projects, and could be used to prevent a project from being inserted twice in the same chain.

There were a few tricks involved, and since it’s been about a month since I worked on this, I’m not sure I can remember all that, and for the time being will simply post the create scripts and hope that they are not too implementation specific and perhaps useful to somebody.

There are two important tables – a Projects table, where each project has an integer projectkey, and then a ProjectsOfProjects table, where each entry has a parent key, a child key, and a grandparent key. If you walk up a chain of records, at some point the grandparent key is null, and that is the end of the chain.

/****** Object: StoredProcedure [dbo].[ProjectAncestors] Script Date: 03/11/2009 17:14:20 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
/*
-- purpose: can we add this child to the specified parent?
-- return false if no, true if yes,
-- returns all the ancestors by recursively calling itself
-- until the last record has a null for the parent key
-- HOW TO RUN:
-- exec ProjectAncestors 40, 30 , 8 , 1
-- Child key - the current project
-- Parent key - the parent project
-- Parent_ikey - the field in the ikey'th record in the ProjectsOfProjects table where the parent's parent is defined
-- (this is the trick that enables us to "walk up" the table and get all the ancestors
SAMPLES: (we had already set up the ProjectsOfProjects table so that there were some children and parents defined)
exec ProjectsOfProjects_ADD 50 , 30, 8 , 1
NOTE - the first execution of [ProjectAncestors] has to have @start=1

declare @OkToInsert bit
exec @OkToInsert = ProjectAncestors 60,30,8,1
print @OkToInsert

exec ProjectAncestors 40, 30 , 8, 1
*/
-- =============================================
CREATE PROCEDURE [dbo].[ProjectAncestors]
@childkey int,
@parentkey int,
@parent_ikey int,
@start int ,
@returncode int OUTPUT

AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
set @returncode = -99

print '******* run [ProjectAncestors] NestLevel=' + convert(varchar(10), @@nestlevel)

declare @Kount int

-- 1) if temp table doesn't exist, then create it
if @start = 1
begin
IF OBJECT_ID('tempdb..#ProjectAncestors') IS NOT NULL drop table #ProjectAncestors

-- set up the table to hold the chain of ancestors
CREATE TABLE #ProjectAncestors (parentkey INT)
-- set up the table to hold the global variable
CREATE TABLE #GlobalVars (childkey INT)
INSERT INTO #GlobalVars (childkey ) VALUES (@childkey )

print ' set the original childkey ' + convert(varchar(10), @childkey)
end

-- 2) go ahead and insert the parameter
INSERT INTO #ProjectAncestors (parentkey ) VALUES (@parentkey )

-- 3) check for the end - when the parent_ikey is null, there are no more relationships defined in the ProjectOfProjects table
if @parent_ikey is NULL
begin
-- a. is it valid to make the relationship? if the desired child was already in the list of ancestors, then it is NOT
-- BUT - remember, this is a recursive procedure, the child key is changing each time we call it. We need to check
-- on the original child key
declare @original_childkey int
select @original_childkey=childkey from #GlobalVars
print ' test the @original_childkey=' + convert(varchar(12),@original_childkey)
select @Kount = count(*) from #ProjectAncestors where parentkey=@original_childkey

-- return the result set
select * from #ProjectAncestors

drop table #ProjectAncestors

print '[ProjectAncestors] just before return @Kount=' + convert(varchar(10),@Kount )
if @Kount > 0
begin
print ' return 0 from [ProjectAncestors]'
print ' the input child record ' + convert(varchar(25), @original_childkey)
print ' was found in the list of ancestors, and therefore cannot be added'
set @returncode = 0
print ' @returncode in [ProjectAncestors]:' + convert(varchar(10),@returncode )
IF OBJECT_ID('tempdb..#ReturnCode') IS NOT NULL
begin
insert into #ReturnCode (returncode) values (@ReturnCode)
end

return 0
end
else
begin
print ' return 1 from [ProjectAncestors]'
print ' the input child record ' + convert(varchar(25), @original_childkey)
print ' was NOT found in the list of ancestors, and therefore CAN be added'
set @returncode = 1
print ' @returncode in [ProjectAncestors]:' + convert(varchar(10),@returncode )
IF OBJECT_ID('tempdb..#ReturnCode') IS NOT NULL
begin
insert into #ReturnCode (returncode) values (@ReturnCode)
end
return 1
end

end

else
begin
print '@parent_ikey is NOT NULL ' + convert(varchar(10),@parent_ikey)

declare @new_parentkey int
declare @new_ikey int
select @new_parentkey=parentkey, @new_ikey=parent_ikey from ProjectsOfProjects where childkey=@parentkey and ikey=@parent_ikey

-- **************************************************************
-- RECURSIVE CALL
-- **************************************************************
-- if it is not null, we recurse
exec projectAncestors @parentkey, @new_parentkey, @new_ikey , 0 , @returncode
end

END

And the structure of the ProjectOfProjects table is:

CREATE TABLE [dbo].[ProjectsOfProjects](
[ikey] [int] IDENTITY(1,1) NOT NULL,
[parentkey] [int] NOT NULL,
[childkey] [int] NOT NULL,
[parent_ikey] [int] NULL,
CONSTRAINT [PK_ProjectsOfProjects] PRIMARY KEY CLUSTERED
(
[ikey] ASC
)

Purge Old Logs

November 21, 2008

I filled a file the other day and got a lot of database errors for one of the tables.
It turned out that my purging process had stopped running (and the notifications weren’t set up).
So I revisited that process, and made two stored procedures to facilitate the process.
Here is how to call the outer procedure:
Exec PurgeOldLogs 30 , 1
30 – number of days
1 – true – actually perform the delete. 0 means just do a select and return the counts that would be deleted.
The outer stored procedure:

-- =============================================

-- input a positive number of days
-- =============================================
CREATE PROCEDURE [dbo].[PurgeOldLogs]
@purgedays int = 60,
@runit bit = 0

AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

exec PurgeASingleLog @purgedays , 'Debugging' , 'dwhen' , @runit
exec PurgeASingleLog @purgedays , 'StatusLog' , 'logdate ' , @runit
exec PurgeASingleLog @purgedays , 'Events' , 'eventtime ' , @runit

END

The inner stored procedure. It generates some dynamic sql and executes it.

GO
/****** Object: StoredProcedure [dbo].[PurgeOldLogs] Script Date: 11/21/2008 07:53:22 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================

-- input a positive number of days
-- =============================================
ALTER PROCEDURE [dbo].[PurgeASingleLog]
@purgedays int = 60,
@tablename varchar(50),
@fieldname varchar(50),
@runit bit = 0

AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

set @purgedays = -1 * @purgedays

declare @cmdcount nvarchar(500)
declare @cmddelete nvarchar(500)

set @cmdcount = 'SELECT count(*) as NumRecords , ' + char(39) + @tablename + char(39) + ' as NameTable '
set @cmdcount = @cmdcount + ' FROM ' + @tablename
set @cmdcount = @cmdcount + ' WHERE (' + @fieldname
set @cmdcount = @cmdcount + ' < DATEADD(d, ' + convert(varchar(12),@purgedays) + ' , GETDATE() ) )'

print @cmdcount

EXECUTE sp_executesql @cmdcount

if @runit = 1
begin

set @cmddelete = 'DELETE FROM ' + @tablename
set @cmddelete = @cmddelete + ' WHERE (' + @fieldname
set @cmddelete = @cmddelete + ' < DATEADD(d, ' + convert(varchar(12),@purgedays) + ' , GETDATE() ) )'

print @cmddelete

EXECUTE sp_executesql @cmddelete

end

END