Check database connections - sql-server

Long story short, we import data from a firebird database to MS SQL, this is imported to a backup database, checks are done to ensure all is well, then the names are switched, so it becomes the live database.
To do this we set the db to single user, sp_renamedb, then set it back to multi-user.
Periodically, this can fail if there is an open connection to either of the DBs. I have adapted the below script, this is to find any connections to the databases in question.
I just want to make sure this is a reliable way to get any connections? Once I have them, I can decide what to do with them.
SELECT DB_NAME(SP.dbid) AS Database_name ,
SP.spid AS SPIDS ,
SP.hostname AS HostName ,
SP.loginame AS LoginID
FROM sys.sysprocesses AS SP
WHERE (
DB_NAME(SP.dbid) = 'Database1'
OR DB_NAME(SP.dbid) = 'Database2'
)
GROUP BY DB_NAME(SP.dbid) ,
SP.spid ,
SP.hostname ,
SP.loginame
ORDER BY DB_NAME(SP.dbid);
Cheers

Related

DB2 - Querying two databases in SQL PL

I need to compare data across two different DB2 database instances. We're not permitted to set up federation. I've found references saying how to specify data loads from remote databases, and also references on how to specify a database connection including database name, username etc. Ideally I would be able to execute a query against one database, then compare that to the second database either one-by-one (using SQL PL loops etc.), or as a single large join. I've gotten to the point where the SQL PL script can connect to each in turn (and it prompts me for the password to both), but it only recognizes the second one when I attempt to query the table.
What we've tried:
Adding two different CONNECT statements at the beginning.
Declaring a cursor and specifying the database name (this seems to only work when doing loads from one database to another, which we're trying to avoid).
set serveroutput on#
set sqlcompat DB2#
connect to first user myname#
connect to second user myname#
-- run command: db2 -td# -vf test3.sql
begin
declare loop_counter int;
call dbms_output.enable(100000);
set loop_counter = 0;
FIRSTLOOP: for o as ord1 cursor for
select field1, field2 from first.firstschema.firsttable fetch first 10 rows only with ur
do
set loop_counter = loop_counter + 1;
call dbms_output.put_line('Field: '||field1||', other '||field2);
end for;
call dbms_output.put_line('End first program: ');
SECONDLOOP: for p as ord2 cursor for
select field1, field2 from second.secondschema.secondtable fetch first 10 rows only with ur
do
set loop_counter = loop_counter + 1;
call dbms_output.put_line('Field: '||field1||', other '||field2);
end for;
call dbms_output.put_line('After second call');
end#
Ideally, each of the two cursor loops would print 10 rows. In reality, whichever CONNECT was done second is the one that works. For example, if I have the connect to SECOND followed by the connect to FIRST, the first loop works and the second says "..... is an undefined name". If I do the connect to FIRST then the connect to SECOND, the first loop throws the error and I get no output.
SQL PL can connnect only to one database at a time - that is the design.
In your script example, the second connect will close any current connection first.
Federation lets you access remote tables as if they were local.
If you are prevented from using federation , your options include these:
materialising the remote table locally and copying the data
(this can be done via load from remote cursor).
You can then use SQL to compare rows, as both tables are then in the same database.
This is only feasible if you have sufficient capacity to fit both tables in same database, although compression will help here.
not using SQL but instead using another tool
For example: depending on data volumes , and data-types, you could export source/target tables
to flat files and compare the files (diff etc). You could also export to pipe and use in memory comparisons.
Or you could use python or perl or any scripting language and do the comparison in memory in chunks (in all cases
each thread can only connect to a single database at one time).
use third party tools for data comparison.
if you use embedded-SQL , type-2 connect offers another possibility.
On Db2 for IBM i, federation is only available via Db2 LUW box...
However, the following works in Db2 for IBM i...
create or replace function myschema.myudtf ()
returns table (SERVER VARCHAR(18)
, as_of timestamp
, ORDINAL_POSITION INTEGER
, JOB_NAME VARCHAR(28)
, SUBSYSTEM VARCHAR(10)
, AUTHORIZATION_NAME VARCHAR(10)
, JOB_TYPE VARCHAR(3)
)
modifies SQL data
external action
not deterministic
language SQL
specific CHKAWSJOBS
begin
declare insertStmt varchar(1500);
declare global temporary table
GLOBAL_TEMP_MY_JOBS (
SERVER VARCHAR(18)
, as_of timestamp
, ORDINAL_POSITION INTEGER
, JOB_NAME VARCHAR(28)
, SUBSYSTEM VARCHAR(10)
, AUTHORIZATION_NAME VARCHAR(10)
, JOB_TYPE VARCHAR(3)
) with replace;
for systemLoop as systemsCursor cursor for
select * from table( values ('mysys1'),('mysys2'),('mysys3'))
as systems (server_Name)
do
set insertStmt =
' insert into GLOBAL_TEMP_MY_JOBS
select
current_server as server, current_timestamp as as_of
, ordinal_position, job_name, subsystem, authorization_name, job_type
from table(QSYS2.ACTIVE_JOB_INFO(
SUBSYSTEM_LIST_FILTER => ''MYSBS'')) X
where exists (select 1 from ' concat server_name concat '.sysibm.sysdummy1)';
execute immediate InsertStmt;
end for;
return select * from GLOBAL_TEMP_MY_JOBS;
end;
The example above is more complex than your use case, I'm pulling data from a UDTF on the remote system, the trick is the use of a 3 part name in the where clause, which forces the DB to run the entire select statement on the remote machine; with the insert being into the table on the local machine.
You should be able to build a dynamic insert that's just
set insertStmt = 'insert into lcltable
select field1, field2
from ' concat server_name concat table_name
concat ' fetch first 10 rows only with ur';
Don't know for sure that this will work on Db2 LUW, but there's a good chance.

SQL Server logs location

How can I retrieve all T-SQL statements fired by users in last one month in SQL Server database?
I have looked at sys tables but I am not able to figure out where the logs are stored.
In SQL Server we don't keep track of users who execute queries, except for some DML/DDL captured by the default trace or run SQL Profiler
Better to create a server side trace or enable SQL Audit to track down activity from users that you want to track or you don't trust.
If you are using any DMV for capture data, remember that DMV data gets reset if the DMV is cleared out, sql server is restarted, etc.
SQL query:
USE master
go
SELECT sdest.DatabaseName
,sdes.session_id
,sdes.[host_name]
,sdes.[program_name]
,sdes.client_interface_name
,sdes.login_name
,sdes.login_time
,sdes.nt_domain
,sdes.nt_user_name
,sdec.client_net_address
,sdec.local_net_address
,sdest.ObjName
,sdest.Query
FROM sys.dm_exec_sessions AS sdes
INNER JOIN sys.dm_exec_connections AS sdec ON sdec.session_id = sdes.session_id
CROSS APPLY (
SELECT db_name(dbid) AS DatabaseName
,object_id(objectid) AS ObjName
,ISNULL((
SELECT TEXT AS [processing-instruction(definition)]
FROM sys.dm_exec_sql_text(sdec.most_recent_sql_handle)
FOR XML PATH('')
,TYPE
), '') AS Query
FROM sys.dm_exec_sql_text(sdec.most_recent_sql_handle)
) sdest
where sdes.session_id <> ##SPID
--and sdes.nt_user_name = '' -- Put the username here !
ORDER BY sdec.session_id
Query Store (SQL Server 2016+) instead of the DMV's. This gives better ability to look into historical data, as well as faster lookups and very efficient to capture short-running queries that can't be captured by sp_who/sp_whoisactive as well.

Tracking deletes on SQL Server

I intend to track delete actions done on a SQL Server DB whose recovery model is simple.
Do such actions get logged when the DB is in this mode?
You can achieve your goal in many different way. If you want you can read delete operations from sql server transaction log, but you will "loose" it after each transaction log backup if you are in full recovery model. In simple recovery model you can not control the transaction log contents.
To find delete operations for a particular table you can use the following query:
DECLARE #MonitoredTable sysname
SET #MonitoredTable = 'YouTable'
SELECT
u.[name] AS UserName
, l.[Begin Time] AS TransactionStartTime
FROM
fn_dblog(NULL, NULL) l
INNER JOIN
(
SELECT
[Transaction ID]
FROM
fn_dblog(NULL, NULL)
WHERE
AllocUnitName LIKE #MonitoredTable + '%'
AND
Operation = 'LOP_DELETE_ROWS'
) deletes
ON deletes.[Transaction ID] = l.[Transaction ID]
INNER JOIN
sysusers u
ON u.[sid] = l.[Transaction SID]
Another approach you can use is to write an "audit trigger" or you can use directly sql server auditing features/Sql server extended events as well explained in this Apex webpage:
SQL Server database auditing techniques

Sql Server - how to get last server restart (DMV reset date/time)

I'm using some modifications to Glenn Berry's excellent DMV queries!
However, I would like to add to the resultset the 'last server restart', or to be more specific, the date/time the statistics for (all, the specific) DMV was reset.
Since it would be quite important to know last reset when looking at the statistics, I want to make absolutely sure the date/time is accurate and shown.
Question: How can you get the most accurate date/time of when a/all DMV statistic was reset?
Thanks!
-D
SELECT sqlserver_start_time FROM sys.dm_os_sys_info
Using a prior question (different key words), I ended up using this approach. As always, up to the individual what would be 'best' for them!
SELECT create_date
FROM sys.databases
WHERE name = 'tempdb'
source: Find out how long the sql server service has been running, from t-sql
This will work but you have to know the service name also its only available with R2 and later
SELECT last_startup_time
FROM sys.dm_server_services
WHERE servicename = "Your Service name"
Although this won't be totally accurate since you can also reset the DB specific views via a DB detach or a DB close.
Also there are two views that can be reset on a live db sys.dm_os_latch_stats and sys.dm_os_wait_stats
There are many ways to check when was SQL server restarted last time.
Below mentioned SQL queries can be used to quickly find out the
server restart date time.
SELECT sqlserver_start_time FROM sys.dm_os_sys_info;
SELECT login_time FROM sys.dm_exec_sessions WHERE session_id = 1;
select start_time from sys.traces where is_default = 1 ;
SELECT crdate FROM sysdatabases WHERE name='tempdb' ;
SELECT create_date FROM sys.databases WHERE name = 'tempdb' ;
There are various way to find out SQL Server reboot time. Following are the codes which return the server re-boot date:
SELECT sqlserver_start_time FROM sys.dm_os_sys_info;
SELECT login_time FROM sys.dm_exec_sessions WHERE session_id = 1;
SELECT start_time from sys.traces where is_default = 1;
SELECT crdate FROM sysdatabases WHERE name='tempdb';
SELECT create_date FROM sys.databases WHERE name = 'tempdb';

inactive databases

On our company's SQL server, there are a bunch of databases that don't appear to be used. Is there a way to determine the last time someone used a particular db, connected to it, or ran a query against it?
I don't think there's a per-database statistic for last used date.
What you can do is attach SQL Server profiler to the database, with a filter on database name. You can leave this running for a few weeks and see if there's any activity.
Another option is to check Database Properties -> Reports -> Standard Reports -> Index Usage Statistics. If the last use of any index is very old, that's a good indication the database is not being used.
Alternatively, have a look at SQL Server Auditing. I haven't used it myself, but it looks like it might suit your needs.
Here is actually a query I use. It tells you what DB was used last since its last restart. It gives a date it was last used and days since it was last used. This should be what you need. It is dynamic and will work on any server because is uses system views. Run this on the master DB.
DECLARE #RESTART DATETIME
SELECT #RESTART = login_time
FROM sysprocesses
WHERE spid = 1
SELECT ##SERVERNAME AS SERVER_NAME
,DB_NAME(db.database_id) AS 'DATABASE'
, db.state_desc AS 'State'
, #RESTART AS 'SYSTEM_RESTART'
, MAX(coalesce(us.last_user_seek, us.last_user_scan, us.last_user_lookup,#RESTART)) AS 'LAST_USE'
,CASE
WHEN DATEDIFF(DAY,#RESTART, MAX(coalesce(us.last_user_seek, us.last_user_scan, us.last_user_lookup,#RESTART))) = 0
THEN 'Prior to restart ' + CONVERT(VARCHAR(5),DATEDIFF(DAY,MAX(coalesce(us.last_user_seek, us.last_user_scan, us.last_user_lookup,#RESTART)), CURRENT_TIMESTAMP)) +' days ago'
ELSE CONVERT(VARCHAR(5),DATEDIFF(DAY,MAX(coalesce(us.last_user_seek, us.last_user_scan, us.last_user_lookup,#RESTART)), CURRENT_TIMESTAMP))
END AS 'DAYS_SINCE_LAST_USE'
FROM sys.databases db
LEFT OUTER JOIN sys.dm_db_index_usage_stats us ON db.database_id = us.database_id
/* IF you want to exclude offlinbe Dbs in your output
then remove the comment '--AND STATE != 6' below.
*/
WHERE db.database_id > 4 --AND STATE != 6
GROUP BY DB_NAME(db.database_id), db.state_desc
ORDER BY DB_NAME(db.database_id)

Resources