Creating an SSRS report identifying database activity - sql-server

I'm trying to create a SQL query that tells if any new tables/views or SP's have been created for a particular month. So far getting the info on any new objects created has been the easy part
select SCHEMA_NAME(schema_id) AS schema_name,
name AS objects_name,
create_date,
modify_date,
type,
so.type_desc,
principal_id
from sys.objects so
where type in ('U','V','P')
and create_date > DATEADD(DAY, -30, CURRENT_TIMESTAMP)
What has been challenging is finding out who created or modified these artefacts. All online sources point to me having to create a trigger on the DB. Is there any query I can run to identify the responsible person.
NB:not the roles but the actual userid
Tried a bunch of queries including a trace:
DECLARE #RC int, #TraceID int, #on BIT
EXEC #rc = sp_trace_create #TraceID output, 2, N'C:\path\file'
SELECT RC = #RC, TraceID = #TraceID
-- Follow Common SQL trace event list and common sql trace
-- tables to define which events and table you want to capture
SELECT #on = 1
EXEC sp_trace_setevent #TraceID, 128, 1, #on
-- (128-Event Audit Database Management Event, 1-TextData table column)
EXEC sp_trace_setevent #TraceID, 128, 11, #on
EXEC sp_trace_setevent #TraceID, 128, 14, #on
EXEC sp_trace_setevent #TraceID, 128, 35, #on
EXEC #RC = sp_trace_setstatus #TraceID, 1
GO

Related

How can I delete a maintenance plan with T SQL?

I have 87 servers that each have maintenance plans that need to be deleted to be replaced with agent jobs. Here's what I've tried:
DECLARE #planId UNIQUEIDENTIFIER;
select #planId = p.id
from msdb..sysmaintplan_plans p
where p.name LIKE 'Night%';
PRINT #planId;
EXEC msdb..sp_delete_maintenance_plan #planId;
and the result that I get:
E0BC518C-CFD4-4BB0-A843-74B61B22B72E
Msg 14262, Level 16, State 1, Procedure sp_delete_maintenance_plan,
Line 12 [Batch Start Line 3] The specified #plan_id
('E0BC518C-CFD4-4BB0-A843-74B61B22B72E') does not exist.
How can I get this to work? Would a powershell script work better?
Besides sp_delete_job, you may also want to have a look at sp_ssis_deletepackage, but this one is not documented. Try using Profiler to see what is called when you delete a maintenance plan.
I have solved this issue by this:
declare #folder_id uniqueidentifier
declare #plan_id uniqueidentifier
declare #plan_name nvarchar (100) = 'Plan Name'
select #plan_id = id from msdb.dbo.sysmaintplan_plans where [name] = #plan_name
select #folder_id = folderid from msdb.dbo.sysssispackages where name = #plan_name
exec msdb.[dbo].sp_ssis_deletepackage #plan_name,#folder_id
exec msdb.[dbo].[sp_maintplan_delete_plan] #plan_id

Why am I getting different results for 2008 sql server and 2014 while tracing "Audit Add Member to DB Role Event"?

I have two sql servers: 2008 and 2014.
When I am trying to collect traces for "Audit Add Member to DB Role" event class, my 2008 server does not capture TextData, but 2014 does capture. But there is no information on msdn about TextData for this event class:
Audit Add Member to DB Role Event Class
Code to create traces:
DECLARE #TraceID int
DECLARE #FILESIZE bigint
set #FILESIZE = 5
DECLARE #FILEPATH nvarchar(256)
SET #FILEPATH = 'C:\Temp\Traces\trace'
DECLARE #StopTime datetime
Set #StopTime = DATEADD( dd, 7, GETDATE())
exec sp_trace_create #TraceId=#TraceID OUT, #options=2, #tracefile=#FILEPATH, #maxfilesize=#FILESIZE, #stoptime=#StopTime
exec sp_trace_setevent #TraceID=#TraceID,#EventId=110,#ColumnId=1,#on=1
exec sp_trace_setstatus #traceid = #TraceID, #status = 1
Where
#EventId=110 - Audit Add Member to DB Role Event Class
#ColumnId=1 - TextData column.
When I execute:
exec sp_addrolemember 'db_accessadmin', 'TESTPC\TestGroup'
exec sp_droprolemember 'db_accessadmin', 'TESTPC\TestGroup'
I am getting results:
For 2008:
For 2014:
Is there any docs that I cant find on the web?

SQL Job with TRY reports success on failure when inserting from remote SP

I've found a way to fail a SQL Scheduled Job (with severity 16) that does not report failure (and so does not send email notifications). I've fixed my immediate issue, but I want to know why there is a failure case that does not report as failure, and if there are any other surprising ways to miss notification.
I've set up two linked servers and am attempting to run an hourly scheduled SQL Job on one that queries the other. I found this morning that the code in the SP had not been running, but the history on the Job was reporting success. The Job's only step is EXEC _testSP. If I ran EXEC _testSP in a query window from SSMS, I received this error message:
Msg 0, Level 11, State 0, Line 0 A severe error occurred on the
current command. The results, if any, should be discarded.
The SP's contents are wrapped in TRY ... CATCH. If I remove the TRY ... CATCH, executing the SP gives up this error message:
Msg 213, Level 16, State 7, Line 1
Insert Error: Column name or number of supplied values does not match table definition.
This made sense. The remote table was referenced with a SELECT * FROM and some columns had been added to it. I've removed the asterix and the job runs fine now, but I want to make sure that all future exceptions get logged either by the job failure notification, or the CATCH block in _testSP. I don't understand why this one didn't get logged, and I hope that someone can explain it to me.
The job runs and fails and notifies just as I would expect when the TRY ... CATCH wrapping is removed, but we have some important things in the TRY ... CATCH that need to be kept.
This is not a duplicate of this related question. The Microsoft BOL for TRY...CATCH says that some exceptions cannot be caught by TRY...CATCH. It may be related, but what I've found is an exception that is not caught by the Scheduled Job agent.
Reproduceable example: (also try removing the TRY...CATCH wrapper and see the change)
USE [RemoteServer].[Database]
CREATE TABLE [Tally](
[ID] [int] IDENTITY(0,1) NOT NULL,
[ID2] [int] NOT NULL
) ON [PRIMARY]
GO
USE [LocalServer]
-- Setup procedure
CREATE PROCEDURE _testSP
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
-- Create destination temp table
CREATE TABLE #tempb (a int)
-- Insert into temp table from remote Tally table
DECLARE #query nvarchar(4000)
SELECT #query = '
SELECT TOP 5 *
FROM [Database].[dbo].Tally
'
INSERT INTO #tempb
EXEC [RemoteServer].[master].[dbo].sp_executesql #query
END TRY BEGIN CATCH
-- Log the exception
-- ...
-- Rethrow the exception
DECLARE #ErrorMessage nvarchar(max), #ErrorSeverity int, #ErrorState int;
SELECT
#ErrorMessage = 'Handled Exception: ' + ERROR_MESSAGE() + ' line ' + CAST(ERROR_LINE() as nvarchar(5)),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState);
END CATCH
END
GO
-- Setup job
DECLARE #database varchar(100)
SELECT #database = DB_Name()
EXEC msdb.dbo.sp_add_job
#job_name = '_testSPJob'
EXEC msdb.dbo.sp_add_jobstep
#job_name = '_testSPJob',
#step_name = '_testSPJob',
#subsystem = N'TSQL',
#command = 'EXEC _testSP',
#database_name = #database
EXEC msdb.dbo.sp_add_jobserver
#job_name = '_testSPJob',
#server_name = ##SERVERNAME
GO
-- Manual execution fails
EXEC _testSP
GO
-- Run job
EXEC msdb.dbo.sp_start_job
#job_name = '_testSPJob'
WAITFOR DELAY '00:00:02'
GO
-- Select job history
SELECT * FROM msdb.dbo.sysjobhistory
WHERE step_name = '_testSPJob'
ORDER BY run_date, run_time
GO
I really need to convince the bosses to get off SQL 2000. Here are my software versions. Perhaps this is fixed in later versions of SQL?
SSMS Version: 2012 (11.0.5058.0)
Local DB: SQL 2005 (9.0.5069)
Remote DB: SQL 2000 (8.0.760)
I think that what is happening is correct, because you're handdling an exception, so the job is not failling. A solution could be a log so when the exception y catch you insert a row with the error description.

Does SQL Profiler work with LocalDB?

Is it possible to use SQL Profiler to observe queries being requested of a LocalDB instance?
You can use SQL Profiler just as you do with all other SQL editions as long as you know the proper server name. You can find the server name using the SqlLocalDb utility.
To find it, use sqllocaldb info YourInstanceName to find the Instance Pipe Name. It has the form np:\\.\pipe\LOCALDB#12345\tsql\query
Use this as the server name to connect to the server and start profiling
This is what I used on SQL Server Express 2012 (note: not "LocalDB* - I have never used LocalDB so maybe that is different to a "regular" SQL Server Express).
Step 1: Setup the trace
This is basically the "hard work". You first need to find out where the default log directory of SQL Server is. You need this directory name to specfiy the trace file.
Then create a trace by doing something like this:
DECLARE #TraceID int
DECLARE #tracefile nvarchar(255)
DECLARE #endDate datetime
DECLARE #size bigint
-- no file extension!
SET #tracefile = 'C:\Data\sqlserver\MSSQL11.SQLEXPRESS\MSSQL\Log\mydb_trace'
-- tracing stops when either the max size of the file is reached
-- or the enddate (whichever occurs first)
-- size is in MB
SET #size = 250
SET #enddate = DateAdd(DAY, 15, GetDate())
EXEC #rc = sp_trace_create #TraceID output, 2, #tracefile, #size, #enddate
Now for every event that should be traced, you need to call sp_trace_setevent multiple times to define which column for that event should be returned:
For a full list of events and columns, see: http://msdn.microsoft.com/en-US/library/ms186265%28v=sql.90%29.aspx
-- Enable Event: 45 = SP:StmtCompleted
EXEC sp_trace_setevent #TraceID, 45, 27, #on -- 27: EventClass
EXEC sp_trace_setevent #TraceID, 45, 12, #on -- 12: SPID
EXEC sp_trace_setevent #TraceID, 45, 35, #on -- 35: DatabaseName
EXEC sp_trace_setevent #TraceID, 45, 11, #on -- 11: SQLSecurityLoginName
EXEC sp_trace_setevent #TraceID, 45, 6, #on -- 6: NTUserName
EXEC sp_trace_setevent #TraceID, 45, 8, #on -- 8: ClientHostName
EXEC sp_trace_setevent #TraceID, 45, 10, #on -- 10: ApplicationName
EXEC sp_trace_setevent #TraceID, 45, 1, #on -- 1: TextData
EXEC sp_trace_setevent #TraceID, 45, 13, #on -- 13: Duration
EXEC sp_trace_setevent #TraceID, 45, 14, #on -- 14: StartTime
EXEC sp_trace_setevent #TraceID, 45, 15, #on -- 15: EndTime
EXEC sp_trace_setevent #TraceID, 45, 18, #on -- 18: CPU
EXEC sp_trace_setevent #TraceID, 45, 29, #on -- 29: Nesting Level
All of the above calls must be done for each and every event you want to trace!
I find the events 12 = SQL:BatchCompleted, 42 = SP:Starting, 43 = SP:Completed, 45 = SP:StmtCompleted, 50 = SQL Transaction the most interesting ones.
Optionally you can setup a filter, I usually filter out system events and only show events for a specific database:
-- Exclude system events (so only user events are shown)
-- 60: IsSystem Column
-- 0: logical Operator: AND (only)
-- 1: comparison operator: not equal
-- 1: value
EXEC sp_trace_setfilter #TraceID, 60, 0, 1, 1
-- only mydb database
EXEC sp_trace_setfilter #TraceID, 35, 0, 6, N'mydb'
Once the trace is setup, it must be activated:
EXEC sp_trace_setstatus #TraceID, 1
(Note the above must be run as a single batch, because of the variable usage).
To see how the trace was defined, you can use the following statement:
select traceid,
case property
when 1 then 'Trace Options'
when 2 then 'Trace file'
when 3 then 'Max. file size'
when 4 then 'Stop time'
when 5 then 'Status'
end as property_name,
case
when property = 5 then
case convert(nvarchar(max), value)
when '1' then 'Active'
else 'Inactive'
end
else convert(nvarchar(max), value)
end as value
from ::fn_trace_getinfo(null)
where property in (2,3,5)
Now run your application or whatever issues statements to the database that you want to trace.
Step 2: Retrieve trace information
For this you need to know the full path to the actual trace file (from Step 1). Note that for fn_trace_gettable you need to specify the file including the file extension.
SELECT ApplicationName,
LoginName,
HostName,
SPID,
Duration,
StartTime,
EndTime,
DatabaseName,
reads,
writes,
RowCounts,
cpu,
EventClass,
case EventClass
when 10 then 'RPC:Completed'
when 11 then 'RPC:Starting'
when 12 then 'SQL:BatchCompleted'
when 13 then 'SQL:BatchStarting'
when 40 then 'SQL:StmtStarting'
when 41 then 'SQL:StmtCompleted'
when 42 then 'SP:Starting'
when 43 then 'SP:Completed'
when 44 then 'SP:StmtStarting'
when 45 then 'SP:StmtCompleted'
when 50 then 'SQL Transaction'
when 67 then 'Execution Warnings'
when 71 then 'Prepare SQL'
when 72 then 'Exec Prepared SQL'
when 73 then 'Unprepare SQL'
end as Event,
LineNumber,
TextData
FROM ::fn_trace_gettable('C:\Data\sqlserver\MSSQL11.SQLEXPRESS\MSSQL\Log\mydb_trace.log', default)
order by StartTime;
Adjust the above to return the information you are interested in.
Once you have the information you need, you have to turn off the trace:
Step 3: disable the trace
For this you need to know the Trace-ID (e.g. by running the "info statement from Step 1). The with this ID, you need to first stop the trace, then you can delete it:
-- stop the trace
EXEC sp_trace_setstatus #TraceID, 0
-- delete the trace
EXEC sp_trace_setstatus #TraceID, 2
From http://expressprofiler.codeplex.com/
ExpressProfiler (aka SqlExpress Profiler) is a simple but good enough replacement for SQL Server Profiler with basic GUI.
No requirements, no installation.
Can be used with both Express and non-Express editions of SQL Server 2005/2008/2008r2/2012 (including LocalDB)
It as simple as setting the server to (LocalDB)\v11.0
http://expressprofiler.codeplex.com/discussions/456518
Microsoft SQL Server 2012 Express LocalDB is an execution mode of SQL Server Express targeted to program developers.
Sql Profiler is not provided with SQL Server Express.
Thus, you can't use Sql profiler for your LocalDB.
However,you can go through alternative ways.
How to use SQL Profiler with SQL Server Express Edition
I had the same issue and following solution worked for me. Open the SQL profiler and connect to the sql server. In the new trace select event selection tab. Then check the show all events check box. After that, from the list select the checkboxes under data base name. Now use column filter then select databasename. Select like and type %localDB%. then start the trace. It will capture every thing on that database.

How to get sum of amount of all databases together through cursor

I am stucking in one place in sql query. I have 20 databases and all database's table name and columns name are same but data is different. I am creating a sql query to get payment amount of particular date from all databases together.
I have many columns in payment table. I need on sum(amount) regarding there paymentTypeID column because I can get amount on the basis of paymentTypeID. All paymentTypeIDs are different in databases but sometimes it is same. I have created a cursor for this.
My code is:
create table #tmpDBs(DBName varchar(255), CurrentDayPaymentAmount float)
declare cDBs cursor for
select name from master.dbo.sysdatabases
declare #DB varchar(255)
open cDBs
fetch next from cDBs into #DB
while ##fetch_status = 0
begin
exec('
declare #DateCurrent datetime
set #DateCurrent = '{Current Date}'
insert into #tmpDBs
select DBName = ' + #DB + ',
CurrentDayPaymentAmount = (select sum(p.amount) from ' + #DB + '.dbo.Payment p where p.eDate between #DateCurrent and dateadd(day, 1, #DateCurrent) and (p.paymenttypeid in (14, 15, 16, 17, 21, 22, 24, 35, 37, 38, 50)))
')
fetch next from cDBs into #DB
end
close cDBs
deallocate cDBs
select * from #tmpDBs
drop table #tmpDBs
I used In clause to pass all databases paymenttypeid together.
This code is for retrieve the payment amount from 2 databases. paymenttypeid 14, 15, 16,17, 22, 24, 38 is for first database and 21, 35, 37, 50 is for second database. My problem is that when I put these paymentTypeID in In clause it adds the amount of matching paymenttypeid of other database.
For example if first database actual amount is 4589$ but it adds additional amount say 5469$ by using second database paymenttypeid. If I pass only one database paymenttypeid it shows the correct amount.
What is the issue in my query.
I think you explained the issue yourself: you want only types 1, 2 and 3 from DB1 and only types 4, 5 and 6 from DB2, but your query doesn't do that, it asks for types 1, 2, 3, 4, 5 and 6 from DB1 and DB2.
That means you need to use a different WHERE clause for each databases, depending on which types you want. So how do you know which types you want from each database and how can you express that logic in your stored procedure?
As a completely different solution, create a view in each database with the correct WHERE clause and then just query the view for your report.

Resources