get the last modifed user for a sql job agent job - sql-server

The schedule for one of my job agents jobs has recently been disabled, is there anyway to find out any information other than last modified date on who or what disabled the job schedule?

SQL Server doesn't audit this information by default, so no, this data is not going to be available to you after the fact. (I checked the default trace and it doesn't seem to be logged there.) If you haven't since re-enabled the job, you may be able to correlate the value in msdb.dbo.sysjobs.modified_date with other information that is logged, but I have no idea what other events you might be able to ascertain belong to the same user as the one who modified the job. Again, if the job hasn't already been modified (or you know when it was modified before you fixed it), and assuming the change happened in the timeframe that is still within your current rolling window for the default trace, you can check for other activity around the same time:
DECLARE #ModifiedDate DATETIME;
SET #ModifiedDate = -- plug in the value here
DECLARE #path NVARCHAR(260);
SELECT #path = REVERSE(SUBSTRING(REVERSE([path]),
CHARINDEX(CHAR(92), REVERSE([path])), 260)) + N'log.trc'
FROM sys.traces WHERE is_default = 1;
SELECT * FROM sys.fn_trace_gettable(#path, DEFAULT)
WHERE EndTime >= DATEADD(MINUTE, -30, #ModifiedDate)
AND EndTime < DATEADD(MINUTE, 30, #ModifiedDate)
ORDER BY EndTime DESC;
You could set up your own server-side trace, extended events session, event notification or audit to make sure that you are able to audit this information in the future (or simply restrict the ability of your whole team to mess with jobs).

The easy part is to find what jobs and/or schedules that have been disabled recently.
-- Use msdb
use msdb
go
-- Jobs that have been recently disabled
select
[name], [enabled], [date_created], [date_modified]
from sysjobs
where [date_modified] > '2013-09-30' and enabled = 0
order by [date_modified] desc
go
-- Schedules that have been recently disabled
select
[name], [enabled], [date_created], [date_modified]
from sysschedules
where [date_modified] > '2013-09-30' and enabled = 0
order by [date_modified] desc
go
Unless the user or sysadmin took ownership of the job, it is hard to find out who did it.
Things that I thought of but did not work were the following.
1 - Any entries in the server or agent logs? NO DICE
2 - Does the default server side trace pickup the event? NO DICE
3 - Can I look at the transaction log to find the person? MSDB uses a simple recovery model. NO DICE
4 - Does the health check (extended events) track this information. Which I doubted, but wanted to check. NO DICE
5 - Since this is not an error, nothing gets logged in windows events. NO DICE
Therefore, after a couple google searches, I think you are down to a couple solutions.
A - Create a trigger on the appropriate system table and save audit information.
See my blog on 'How to audit and prevent unwanted user actions.'. It is a full blown presentation that I do at SQL Saturdays.
B - Create a http://www.bimonkey.com/2009/12/sql-server-2008-auditing/ audit specification but you will have to read the output file.
C - Add a server side trace or extended event to capture the data.
Good luck.
John

Related

SQL Server : how to automatically update data in table after a certain time interval

I have an OrderProduct table with these columns and some data:
-order_number : ORDER01
-customer_name : Jackie
-order_status : Wait For Payment
-datetime_order_status : 25-01-2020 15:30:00
-datetime_transfer_notify : NULL
A customer needs to transfer notify in my order product system in 24 hours if not the Microsoft SQL will automatic update data in column 'order_status' from 'Wait for payment' to 'Cancel'.
How can I do that?
I believe the easiest way to do this is with a SQL Agent job (MS Docs). This is very dependent on the architecture and size of your databases and tables, but it would definitely get the job done. Depending on how sensitive the business is to being up to date, you could set the job to run every 1 minute, every 5 minutes, or any other time interval you would like. If I was going to do this, I would use a query along the lines of the following:
UPDATE OrderProduct SET order_state = 'Cancel' WHERE datetime_order_status < DATEADD(DAY, -1, GETDATE()) AND order_status = 'Wait for Payment'
Along with this, I would use something like SQL Server Management Studio to create a SQL Agent job on that server that ran at the interval you'd like, similar to this (Stack Overflow). Here (Stack Exchange DBA) is a very similar question to yours for MySQL as added reference.

Monitoring specific queries in SQL Server

Is there a way to monitor specific SQL queries in SQL Server?
For example I would like to get notified somehow when somebody run a specific query against the database. For eg.:
Select *
from table
where id = 1
Thank You!
There are a couple of ways you can do this. I'd probably start with an audit. Create a server audit.
USE [master]
GO
USE [master]
GO
CREATE SERVER AUDIT [audit_stackoverflow_question]
TO APPLICATION_LOG
WITH (QUEUE_DELAY = 1000, ON_FAILURE = FAIL_OPERATION)
ALTER SERVER AUDIT [stack] WITH (STATE = OFF)
GO
Create a database audit specification.
USE [<your_database>]
GO
CREATE DATABASE AUDIT SPECIFICATION [audit_monitor_dbo.table]
FOR SERVER AUDIT [audit_stackoverflow_question]
ADD (SELECT ON OBJECT::[dbo].[table] BY [public])
WITH (STATE = OFF)
GO
Enable the audit and database audit specification when you're ready. After that point, activity will be logged (in this case to the application event log):
You can push activity to a file. Whatever floats your boat. And, after that, you can Powershell out whatever specific activity you want to see.
You can use extended events or traces for this too, but I think an audit is the way to go.
If you're looking after the fact, check the cache tables:
SELECT t.[text]
, *
FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t
WHERE t.[text] LIKE N'Select%from%table%where%id%'
OPTION (recompile);

Can you Grant select permission to all tables in sql server for a limited time?

So i'm doing this SQL SERVER school project and i want to add to a specific user the right to select for a limited amount of time lets say till 24 September 2016.
Is it possible and if yes how ?
THANKS!
There is no provision to grant access for a limited amount of time.
Best of luck.
The only way I can think of is creating a SQL Server Agent Job.
Create 2 steps in the job one for adding the user to database role db_datareader and then anotehr step to take away the role membership of that user.
The step to grant user permission should look something like
IF (GETDATE() >= '2016-09-24 08:58:59.000'
AND GETDATE() <= '2016-09-24 09:01:00.000')
BEGIN
EXEC sp_addrolemember N'db_datareader', N'UserA'
END
The second step to revoke user's permission should look something like
IF (GETDATE() >= '2016-09-24 16:58:59.000')
BEGIN
EXEC sp_droprolemember N'db_datareader', N'UserA'
END
Schedule the job to run twice a day. Occurrence every 8 hours. Assuming you only want the user to have access for 8 hours.
In the start date and end date options use 24 September 2016. So the Job is only executed on that date and never before or after that date.
Make sure that the interval between occurrences matches the logic in your IF statement of each step.
The job database context should be the database where your user need permissions.
I'd write a job that will run on that date that revokes the user's right.
I would NOT modify the schema to handle a one-off case. Control of rights to the database should be external to the database.
You can create a new column with a date datatype and call it endDate. You'd insert September 24, 2016 into endDate for a user and (depending on how you're accessing it) simply use an if statement comparing the current date and the end date. For example :-
if(CURDATE() < endDate)

How to delete a table after a period of inactivity?

For the purpose of my project I cannot use session based temp tables. They need to be persistent but automatically deleted after a certain period of inactivity (no CRUD performed). Is this at all possible?
You can use the SQL Server Agent to Schedule a Job that calls a Stored Procedure that does this work for you. (How to Schedule a Job?)
How do you identify the tables that have not updated since X amount of time ?
Use this Query:
SELECT OBJECT_NAME(OBJECT_ID) AS TableName, last_user_update,
FROM sys.dm_db_index_usage_stats
WHERE database_id = DB_ID('DatabaseName')
AND OBJECT_NAME(OBJECT_ID) LIKE '%%' -- Here is the template name for your tables
AND DATEDIFF(MINUTE, last_user_update, GETDATE()) > 10 -- Last updated more than 10 minutes
Now that you have the tables to be deleted, you can use whatever logic you want to DROP them (Cursor, While, Procedure)
Sure it is. Write it into your program layer.
AUTOMATICALLY - within SQL Server: no. Well, you cold use the agent to start a script regularly.
Tracking what "inactivity" means - your responsibility.
You need save modification date of this table somewhere (for example in the same table or in another special table) and then you can create job, which checks last modification date and then drops the table.

Tracking User activity log for SQL Server database

I have a database with multiple tables and I want to log the users activity via my MVC 3 web application.
User X updated category HELLO. Name changed from 'HELLO' to 'Hi There' on 24/04/2011
User Y deleted vehicle Test on 24/04/2011.
User Z updated vehicle Bla. Name changed from 'Blu' to 'Bla' on 24/04/2011.
User Z updated vehicle Bla. Wheels changed from 'WheelsX' to 'WheelsY' on 24/04/2011.
User Z updated vehicle Bla. BuildProgress changed from '20' to '50' on 24/04/2011
My initial idea is to have on all of my actions that have database crud, to add a couple lines of code that would enter those strings in a table.
Is there a better way of checking which table and column has been modified than to check every column one by one with if statements (first I select the current values, then check each of them with the value of the textbox) I did that for another ASPX web app and it was painful.
Now that I'm using MVC and ADO.NET Entity Data Model I'm wondering if a faster way to find the columns that were changed and build a log like the one above.
You can also accomplish this by putting your database into full recovery mode and then reading the transaction log.
When database is in a full recovery mode then sql server logs all Update, insert and delete (and others such as create, alter, drop..) statements into it's transaction log.
So, using this approach you dont need to make any additinal changes to your application or your database structure.
But you will need 3rd party sql transaction log reader. Red gate has a free solution for sql server 2000 only. If your server is 2005 or higher you would probably want to go with ApexSQL Log
Also, this approach will not be able to audit select statements but it's definately the easiest to implement if you dont really need to audit select queries.
The way I see, you have two options:
Create triggers in the database side, mapping changes in a table by table basis and getting result into a Log table
OR
Having the code handle the changes. You would have a base class with data and with reflection you could iterate all object properties and see what has changed. And then save that into your Log table. Of course, that coding would be on your Data Access Layer.
By the way, if you have a good code structure/architecture, I would go with the second option.
You could have a trigger (AFTER insert/update/deelte) on each table you want to monitor. The beauty is columns_updated() which returns a barbinary value, indicating which columns have been updated.
Here is some snippet of code that I put in each trigger:
IF (##ROWCOUNT = 0) return
declare #AuditType_ID int ,
#AuditDate datetime ,
#AuditUserName varchar(128),
#AuditBitMask varbinary(10)
select #AuditDate = getdate() ,
#AuditUserNAme = system_user,
#AuditBitMask = columns_updated()
-- Determine modification type
IF (exists (select 1 from inserted) and exists (select 1 from deleted))
select #AuditType_ID = 2 -- UPDATE
ELSE IF (exists (select * from inserted))
select #AuditType_ID = 1 -- INSERT
ELSE
select #AuditType_ID = 3 -- DELETE
(record this data to your table of choice)
I have a special function that can decode the bitmask values, but for some reason it is not pasting well here. Message me and I'll email it to you.

Resources