Can a query be used to list the creators of user-defined functions and stored procedures on Microsoft SQL Server? If so, how?
Assuming it's possible, I'm not sure which Catalog Views to use. I searched Google, but because the word "user" is in the search, I get mountains of unrelated results pertaining to user-defined functions in general.
Can a query be used to list the creators of scalar-valued functions?
yes, but it might be very complex task.
The simpler case: using build in default trace
When we install SQL Server then by default a default trace is created and enabled. In this case, the server logs data necessary to diagnose problems the first time they occur and this include the requested information.
You can read more about this Default Trace here:
https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/default-trace-enabled-server-configuration-option?view=sql-server-ver15&WT.mc_id=DP-MVP-5001699
A short tour:
-- check if default trace enable
SELECT* FROM sys.configurations WHERE configuration_id = 1568
GO
-- Enable default trace:
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'default trace enabled', 1;
GO
RECONFIGURE;
GO
-- start new trace (clean trace for the sake of learning and executing demo)
Exec sp_configure 'show advanced options', 1
Reconfigure
Exec sp_configure 'default trace', 0
Reconfigure
Exec sp_configure 'default trace', 1
Reconfigure
GO
-- List all traces files in the server (is_default = 1 ; active trace)
SELECT * FROM sys.traces
GO
-- Read the information (should be clean now)
DECLARE #path NVARCHAR(260)
SELECT #path=path FROM sys.traces WHERE is_default = 1
PRINT #path
SELECT TE.name AS EventName, DT.DatabaseName, DT.ObjectName, DT.ApplicationName, DT.LoginName,*
FROM sys.fn_trace_gettable (#path, DEFAULT) DT
INNER JOIN sys.trace_events TE ON DT.EventClass = TE.trace_event_id
where DatabaseID = DB_ID() and ObjectName = 'TestingByRonen'
GO
-- Do some task
drop table if exists TestingByRonen
go
create table TestingByRonen(id int)
GO
-- Read the information (new information about our task)
DECLARE #path NVARCHAR(260)
SELECT #path=path FROM sys.traces WHERE is_default = 1
PRINT #path
SELECT TE.name AS EventName, DT.DatabaseName, DT.ObjectName, DT.ApplicationName, DT.LoginName,*
FROM sys.fn_trace_gettable (#path, DEFAULT) DT
INNER JOIN sys.trace_events TE ON DT.EventClass = TE.trace_event_id
where DatabaseID = DB_ID() and ObjectName = 'TestingByRonen'
GO
The limitation
(1) Default trace might not be enabled in advance
(2) Trace might have been drops
(3) This feature will be removed in a future version of Microsoft SQL Server.
Option 2: undocumented
All the information is well logged in the transaction log and if you kept the backup of the transaction log then even history data can be find directly from backup
For example, the following sample find Who created the database:
https://ariely.info/Blog/tabid/83/EntryId/303/SQL-Server-Who-created-the-database.aspx
Example 2: The following post presents Who deleted my record last time from the table
https://ariely.info/Blog/tabid/83/EntryId/154/SQL-Server-Who-deleted-my-record-last-time.aspx
There are tens of practical uses of parsing the transactional log file.
I Configured a distribution in SQL Server 2008 using both Wizard and T-SQL but after it when I want to remove it Using Wizard (right clicking on Replication and choosing 'Disable Publishing and Distribution...') or executing following command with and without its parameters:
exec sp_dropdistributor #no_checks = 1 -- no new results with #ignore_distributor = 1
this Error would be presented:
Msq 21122, Level 16, State 1, Procedure sp_dropdistributiondb Line 124
Cannot drop the distribution database 'lobloblob' because it is
currently in use.
I didn't publish any thing, didn't configure any subscription but gave this error
what should I do ?
Try this:
SELECT spid FROM sys.sysprocesses WHERE dbid = db_id('distribution')
Kill the spid and try again. Now it should work.
I used the following scripts:
SELECT spid FROM sys.sysprocesses WHERE dbid = db_id('distribution')
and found that the session_id of current session (which contains the distribution configuration script) doesn't allow to disable distribution so i suggest this script to kill running spid to drop distribution:
use [master]
declare #spid varchar(10)
select #spid=spid from sys.sysprocesses where dbid = DB_ID('distribution')
while ##ROWCOUNTS <> 0
exec ('KILL ' + #spid)
exec sp_dropdistributor #no_checks = 1
My guess would be that the distribution cleanup job is causing the problem. But, to check, prepare to execute the sp_dropdistributor in one window in SSMS and note the session_id of the window. In a second, prepare to run select session_id from sys.dm_os_waiting_tasks where blocked_session_id = <spid from window 1>. Back in window 1, run the proc and then switch back to window 2 and run the select. it'll tell you the session_ids of the sessions blocking the drop of the database.
I'm using this query to find some queries that have been running for a long time:
SELECT sqltext.TEXT,
req.session_id,
req.status,
req.command,
req.cpu_time,
req.total_elapsed_time
FROM sys.dm_exec_requests req
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sqltext
order by req.total_elapsed_time des
Currently, we have some xp_cmdshell things that seem to be stuck (we use it to call bcp.exe for bulk exporting in jobs). However, the output of sys.dm_exec_sql_text() only outputs "xp_cmdshell" and not the parameters -- I really would like to see exactly what commands xp_cmdshell is running so I can track down the issues.
Is there any way to do that in SQL server?
EDIT: The active sessions are calling xp_cmdshell from a stored procedure. E.g.:
EXEC usp_xxx -> calls EXEC usp_yyy -> calls xp_cmdshell.
So, the output of DBCC InputBuffer is the call to usp_xxx which is not what I want.
I'm not sure if the details are available in any of the dynamic management views, but you could take your session_id and use it with DBCC INPUTBUFFER to get the details you seek.
DBCC INPUTBUFFER(83)
would return something like this as an example
EventType Parameters EventInfo
-------------- ---------- ------------------------
Language Event 0 EXEC xp_cmdshell 'sc /h'
I am using the Context_Info() variable to keep track of the user that is executing a stored procedure and free-form sql. When troubleshooting issues on this server everyone session comes through. I would like to be able to bring in the value of the context_info() variable and filter based on it.
You can use the UserConfigurable Events along with sp_trace_generateevent (EventId's 82-91) when setting the context_info() to output the values to the trace. Your option is to either do that, or trace the statements setting the context_info(). You won't be able to get the value any other way unless you write a process to dump the output of sys.dm_exec_sessions in a loop while the trace is running:
select session_id, cast(context_info as varchar(128)) as context_info
from sys.dm_exec_sessions
where session_id > 50 -- user sessions
for SQL 2000 you can use sysprocesses:
select spid, cast(context_info as varchar(128)) as context_info
from sysprocesses
where sid > 50 -- user sessions
I want to rename a database, but keep getting the error that 'couldn't get exclusive lock' on the database, which implies there is some connection(s) still active.
How can I kill all the connections to the database so that I can rename it?
The reason that the approach that Adam suggested won't work is that during the time that you are looping over the active connections new one can be established, and you'll miss those. You could instead use the following approach which does not have this drawback:
-- set your current connection to use master otherwise you might get an error
use master
ALTER DATABASE YourDatabase SET SINGLE_USER WITH ROLLBACK IMMEDIATE
--do you stuff here
ALTER DATABASE YourDatabase SET MULTI_USER
Script to accomplish this, replace 'DB_NAME' with the database to kill all connections to:
USE master
GO
SET NOCOUNT ON
DECLARE #DBName varchar(50)
DECLARE #spidstr varchar(8000)
DECLARE #ConnKilled smallint
SET #ConnKilled=0
SET #spidstr = ''
Set #DBName = 'DB_NAME'
IF db_id(#DBName) < 4
BEGIN
PRINT 'Connections to system databases cannot be killed'
RETURN
END
SELECT #spidstr=coalesce(#spidstr,',' )+'kill '+convert(varchar, spid)+ '; '
FROM master..sysprocesses WHERE dbid=db_id(#DBName)
IF LEN(#spidstr) > 0
BEGIN
EXEC(#spidstr)
SELECT #ConnKilled = COUNT(1)
FROM master..sysprocesses WHERE dbid=db_id(#DBName)
END
Kill it, and kill it with fire:
USE master
go
DECLARE #dbname sysname
SET #dbname = 'yourdbname'
DECLARE #spid int
SELECT #spid = min(spid) from master.dbo.sysprocesses where dbid = db_id(#dbname)
WHILE #spid IS NOT NULL
BEGIN
EXECUTE ('KILL ' + #spid)
SELECT #spid = min(spid) from master.dbo.sysprocesses where dbid = db_id(#dbname) AND spid > #spid
END
Using SQL Management Studio Express:
In the Object Explorer tree drill down under Management to "Activity Monitor" (if you cannot find it there then right click on the database server and select "Activity Monitor"). Opening the Activity Monitor, you can view all process info. You should be able to find the locks for the database you're interested in and kill those locks, which will also kill the connection.
You should be able to rename after that.
I've always used:
ALTER DATABASE DB_NAME SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
SP_RENAMEDB 'DB_NAME','DB_NAME_NEW'
Go
ALTER DATABASE DB_NAME_NEW SET MULTI_USER -- set back to multi user
GO
ALTER DATABASE [Test]
SET OFFLINE WITH ROLLBACK IMMEDIATE
ALTER DATABASE [Test]
SET ONLINE
Take offline takes a while and sometimes I experience some problems with that..
Most solid way in my opinion:
Detach
Right click DB -> Tasks -> Detach...
check "Drop Connections"
Ok
Reattach
Right click Databases -> Attach..
Add... -> select your database, and change the Attach As column to your desired database name.
Ok
Select 'Kill '+ CAST(p.spid AS VARCHAR)KillCommand into #temp
from master.dbo.sysprocesses p (nolock)
join master..sysdatabases d (nolock) on p.dbid = d.dbid
Where d.[name] = 'your db name'
Declare #query nvarchar(max)
--Select * from #temp
Select #query =STUFF((
select ' ' + KillCommand from #temp
FOR XML PATH('')),1,1,'')
Execute sp_executesql #query
Drop table #temp
use the 'master' database and run this query, it will kill all the active connections from your database.
I usually run into that error when I am trying to restore a database I usually just go to the top of the tree in Management Studio and right click and restart the database server (because it's on a development machine, this might not be ideal in production). This is close all database connections.
In MS SQL Server Management Studio on the object explorer, right click on the database. In the context menu that follows select 'Tasks -> Take Offline'
Another "kill it with fire" approach is to just restart the MSSQLSERVER service.
I like to do stuff from the commandline. Pasting this exactly into CMD will do it:
NET STOP MSSQLSERVER & NET START MSSQLSERVER
Or open "services.msc" and find "SQL Server (MSSQLSERVER)" and right-click, select "restart".
This will "for sure, for sure" kill ALL connections to ALL databases running on that instance.
(I like this better than many approaches that change and change back the configuration on the server/database)
Here's how to reliably this sort of thing in MS SQL Server Management Studio 2008 (may work for other versions too):
In the Object Explorer Tree, right click the root database server (with the green arrow), then click activity monitor.
Open the processes tab in the activity monitor, select the 'databases' drop down menu, and filter by the database you want.
Right click the DB in Object Explorer and start a 'Tasks -> Take Offline' task. Leave this running in the background while you...
Safely shut down whatever you can.
Kill all remaining processes from the process tab.
Bring the DB back online.
Rename the DB.
Bring your service back online and point it to the new DB.
The option working for me in this scenario is as follows:
Start the "Detach" operation on the database in question. This wil open a window (in SQL 2005) displaying the active connections that prevents actions on the DB.
Kill the active connections, cancel the detach-operation.
The database should now be available for restoring.
Try this:
ALTER DATABASE [DATABASE_NAME]
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE
Right click on the database name, click on Property to get property window, Open the Options tab and change the "Restrict Access" property from Multi User to Single User. When you hit on OK button, it will prompt you to closes all open connection, select "Yes" and you are set to rename the database....
These didn't work for me (SQL2008 Enterprise), I also couldn't see any running processes or users connected to the DB. Restarting the server (Right click on Sql Server in Management Studio and pick Restart) allowed me to restore the DB.
I'm using SQL Server 2008 R2, my DB was already set for single user and there was a connection that restricted any action on the database. Thus the recommended SQLMenace's solution responded with error. Here is one that worked in my case.
I use sp_who to get list of all process in database. This is better because you may want to review which process to kill.
declare #proc table(
SPID bigint,
Status nvarchar(255),
Login nvarchar(255),
HostName nvarchar(255),
BlkBy nvarchar(255),
DBName nvarchar(255),
Command nvarchar(MAX),
CPUTime bigint,
DiskIO bigint,
LastBatch nvarchar(255),
ProgramName nvarchar(255),
SPID2 bigint,
REQUESTID bigint
)
insert into #proc
exec sp_who2
select *, KillCommand = concat('kill ', SPID, ';')
from #proc
Result
You can use command in KillCommand column to kill the process you want to.
SPID KillCommand
26 kill 26;
27 kill 27;
28 kill 28;
You can Use SP_Who command and kill all process that use your database and then rename your database.