<ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll Newtonsoft.Json Newtonsoft.Json.Converters Newtonsoft.Json.Linq Newtonsoft.Json.Schema Newtonsoft.Json.Serialization System System.Diagnostics System.Diagnostics.Tracing System.Dynamic System.IO.Compression System.Threading.Tasks System.Data.Common #region *** Enumerations *** public enum QueryRegions { Production, Training, Oak, Dev } #endregion #region *** Options *** public static QueryRegions queryRegion = QueryRegions.Production; public static string crossDBQueryPath = @"D:\CrossDBQueries"; // This is the path to find the queries public static bool dumpSmcSql = false; // This flag will dump the smc sql to the result public static bool dumpDBList = false; // This flag will dump the databases to the result public static bool dumpQueries = true; // This flag will dump the queries to the result public static bool dumpDBExclusions = false; // This flag will dump the db and server exclusions public static bool dumpDBTargets = false; // This flag will dump the db and server targets public static bool dumpAppVersions = false; // This flag will dump the app versions used in the queryRegion public static bool dumpAppVersionTargets = false; // This flag will dump the app versions targets public static bool excludeExceptions = true; public static bool queryCompress = false; public static bool flatten = true; // This will flatten all of the results into a single list public static bool showStopWatch = false; public static bool noQueries = false; // This will stop the CrossDBQuery without running the queries public static bool useParms = true; #endregion public static Parms parms = new Parms { name = "FY2020" }; #region *** Database Selection *** public static string[] appVersions = { // This is a list of appVersions to filter for in the database list //"2019.42" }; public static string[] serverExclusions = { // This is a list of servers to exclude from the database list @"paonsql19.sdt.local\instance1", @"paonsql17.sdt.local\instance1", @"p0555-sql-01.sdt.local\instance1", "P0000-sql-01.sdt.local", "P9900-SQL-03.sdt.local", "P9900-sql-05.sdt.local" }; public static string[] dbExclusions = { // This is a list of database physical names to exclude from the database list // "jazz tst Team AP Training 01", // "jazz tst Team AP Training 02", // "jazz tst Team AP Training 11", // "jazz tst Team AP Training 12", // "jazz tst Team AP Training 13", // "jazz tst Team AP Training 14" }; public static string[] targetOrgPins = { // This is a list of org pins to target in the database list }; public static string[] targetServers = { // This is a list of servers to target in the database list // "P9900-SQL-11.sdt.local" }; public static string[] targetDBs = { // This is a list of database physicial names to target in the database list // "jazz prd Gillette Childrens 20150417.1" // "jazz prd Southern Illinois 20140408.1" // "jazz tst Southern Illinois 20190918.1" // "jazz dev master Prod" }; #endregion *** Options *** #region *** SMC Settings and queries *** public static string smcSql => @"SELECT di.ServerName, di.DatabaseGUID, di.DatabaseName, di.PhysicalName, di.OrgPin, di.AppVersion, di.Description FROM [dbo].[viewDatabaseInfo] di WHERE 1=1" + (queryRegion == QueryRegions.Dev ? @" AND di.PhysicalName like 'jazz%'" : $@" AND di.PhysicalName like 'jazz {(queryRegion != QueryRegions.Production ? "tst" : "prd")}%' AND di.ServerName like 'p%'"); public static string smcServer { get; set; } public static string smcDB { get; set; } #endregion #region *** Program variables and settings *** public static int maxThreads = 8; public static int timeoutInMinutes = 2; public static IList crossDBQueryResults = new List(); public static IOrderedEnumerable databases => GetDatabases(); public static Dictionary> queries = System.IO.Directory.Exists(crossDBQueryPath) ? GetUserQueries(crossDBQueryPath) : new Dictionary>(); #endregion void Main() { if (dumpDBExclusions) { dbExclusions.Dump(nameof(dbExclusions)); serverExclusions.Dump(nameof(serverExclusions)); } if (dumpDBTargets) { targetOrgPins.Dump(nameof(targetOrgPins)); targetDBs.Dump(nameof(targetDBs)); targetServers.Dump(nameof(targetServers)); } if (dumpAppVersionTargets) { appVersions.Dump(nameof(appVersions)); } if (dumpDBList) { databases.OrderBy(d => d.Server).ThenBy(d => d.PhysicalName).Dump($"{queryRegion} {nameof(databases)}"); } if (dumpAppVersions) { databases .GroupBy(db => db.AppVersion, (grp, data) => data.Select(x => x.AppVersion).First()) .OrderByDescending(db => db) .Dump($"{queryRegion} {nameof(appVersions)}"); } if (noQueries) return; var results = ExecuteCrossDBQueries() //.Where(r => !r.Exceptions.Any() && (r.Results.First().Results.First().Count() != 2).Any()) //.Where(r => !r.Exceptions.Any() && r.Results.First().Name.Contains("Variation")) .OrderBy(dbqr => dbqr.Results.Any() ? 0 : 1) .ThenBy(dbqr => dbqr.Database.DatabaseName); if (flatten) { results .SelectMany(dbqr => dbqr.Results.SelectMany(r => r.Results).ToList()) .Dump(nameof(crossDBQueryResults)); } else { results.Dump(nameof(crossDBQueryResults)); } } public class Parms { public string name { get; set; } } #region *** Other classes *** public class CrossDBQueryResultLite { public Database Database { get; set; } public List Results { get; set; } } public class CrossDBQueryResult : CrossDBQueryResultLite { public List Exceptions { get; set; } public CrossDBQueryResult() { Results = new List(); Exceptions = new List(); } public CrossDBQueryResult(Database database, string name, IEnumerable enumerable) : this() { Database = database; Results.Add(new SqlResults(name, enumerable)); } public CrossDBQueryResult(Database database, Exception exception) : this() { Database = database; Exceptions.Add(exception.ExceptionMessage()); } object ToDump() => excludeExceptions ? (object)new { Database, Results } : new { Database, Results, Exceptions }; } public class SqlResults { public string Name { get; set; } public IEnumerable Results { get; set; } public SqlResults(string name, IEnumerable results) { Name = name; Results = results; } } public static class ExceptionExtension { public static string ExceptionMessage(this Exception exception) { return $@"{exception.Message}{(exception.InnerException != null ? $@" {"".PadLeft(40, '-')} {exception.InnerException.ExceptionMessage()}" : "")}"; } } public class Database { public string Server { get; set; } public Guid DatabaseGuid { get; set; } public string DatabaseName { get; set; } public string PhysicalName { get; set; } public string OrgPin { get; set; } public string AppVersion { get; set; } public string Description { get; set; } public Dictionary Fields { get; set; } public Database() { } public Database(DataRow dr) { Server = dr.Field("ServerName"); DatabaseGuid = dr.Field("DatabaseGuid"); DatabaseName = dr.Field("DatabaseName"); PhysicalName = dr.Field("PhysicalName"); OrgPin = dr.Field("OrgPin"); AppVersion = dr.Field("AppVersion"); Description = dr.Field("Description"); Fields = new Dictionary(); foreach (DataColumn column in dr.Table.Columns) { var index = dr.Table.Columns.IndexOf(column); Fields.Add(column.ColumnName, dr[index].ToString()); } } object ToDump() => (object)new { Server, DatabaseGuid, DatabaseName, PhysicalName, OrgPin, AppVersion, Description }; } public class ThreadWithState { private string connectionString => BuildConnectionString(_server, _databaseName); private Database _database; private string _server => _database?.Server ?? string.Empty; private string _databaseName => _database?.PhysicalName ?? string.Empty; private string sqlName; private IEnumerable _sqlQueries; public ThreadWithState(Database database, KeyValuePair> sqlqueries) { _database = database; sqlName = sqlqueries.Key; _sqlQueries = sqlqueries.Value; } public void ThreadProc() { var crossDB = crossDBQueryResults.FirstOrDefault(x => x.Database == _database); IEnumerable ThreadResults; foreach (var sqlQuery in _sqlQueries) { try { ThreadResults = SelectDynamic(_database, connectionString, sqlQuery); var result = ThreadResults.First(); if (crossDB != null) { crossDB.Results.Add(new SqlResults(sqlName, ThreadResults)); } else { crossDB = new CrossDBQueryResult(_database, sqlName, ThreadResults); crossDBQueryResults.Add(crossDB); } } catch (Exception ex) { if (crossDB != null) { crossDB.Exceptions.Add(new Exception(sqlQuery, ex).ExceptionMessage()); } else { crossDBQueryResults.Add(new CrossDBQueryResult(_database, new Exception(sqlQuery, ex))); } } } } } #endregion #region *** Other methods here *** public static IOrderedEnumerable GetDatabases() { switch (queryRegion) { case QueryRegions.Production: smcServer = "ioak-sql-smc-01"; smcDB = "smc prod"; break; case QueryRegions.Training: smcServer = "ioak-sql-smc-01"; smcDB = "smc training"; break; case QueryRegions.Oak: smcServer = "ioak-sql-smc-01.sdt.local"; smcDB = "smc qa"; break; default: smcServer = "DDEN-SQL-SMC-01.sdt.local"; smcDB = "smc dev"; break; } if (dumpSmcSql) smcSql.Dump(nameof(smcSql)); List databases = new List(); var connStr = BuildConnectionString(smcServer, smcDB); using (var conn = new SqlConnection(connStr)) { var command = new SqlCommand(smcSql, conn); command.CommandType = CommandType.Text; var database = new DataSet(); conn.Open(); using (DbDataReader reader = command.ExecuteReader()) { while (true) { var table = new DataTable(); database.Tables.Add(table); table.Load(reader); if (reader.IsClosed || !reader.NextResult()) break; } } conn.Close(); databases = database.Tables[0].AsEnumerable().Select(dr => new Database(dr)).ToList(); databases = databases.Where(dr => !dbExclusions.Contains(dr.PhysicalName) && !serverExclusions.Contains(dr.Server)).ToList(); if (targetOrgPins.Any()) databases = databases.Where(dr => targetOrgPins.Contains(dr.OrgPin)).ToList(); if (targetServers.Any()) databases = databases.Where(dr => targetServers.Contains(dr.Server)).ToList(); if (targetDBs.Any()) databases = databases.Where(dr => targetDBs.Contains(dr.PhysicalName)).ToList(); if (appVersions.Any()) databases = databases.Where(dr => appVersions.Contains(dr.AppVersion)).ToList(); } return databases .OrderBy(d => d.Server).ThenBy(d => d.PhysicalName); } public static Dictionary> GetUserQueries(string path = null) { var grp = 0; var queries = Directory.GetFiles(path ?? Directory.GetCurrentDirectory(), "*.sql", SearchOption.TopDirectoryOnly) .ToDictionary(d => Path.GetFileNameWithoutExtension(d), f => File.ReadAllLines(f) .Select(r => { if (r.Equals("go", StringComparison.CurrentCultureIgnoreCase)) { r = ""; return new { grp = grp++, r }; } else { return new { grp, r }; } }).GroupBy(r => r.grp, (x, lines) => string.Join(queryCompress ? " " : "\r\n", lines.Select(l => l.r).Where(l => !string.IsNullOrEmpty(l))))); // foreach (var key in queries.Keys) // { // foreach (var query in queries[key]) // { // if (useParms) // { // FormattableString formatter = $""; // string.Format(formatter, parms).Dump(); // } // } // } if (dumpQueries) queries.Dump(nameof(queries)); return queries; } public static IEnumerable SelectDynamic(Database db, string connStr, string sql) { using (var conn = new SqlConnection(connStr)) { var command = new SqlCommand(sql, conn); command.CommandType = CommandType.Text; command.CommandTimeout = (int)TimeSpan.FromMinutes(timeoutInMinutes).TotalSeconds; var database = new DataSet(); conn.Open(); using (DbDataReader reader = command.ExecuteReader()) { while (true) { var names = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList(); foreach (IDataRecord record in reader as IEnumerable) { var expando = new ExpandoObject() as IDictionary; if (flatten) db.Fields.ForEach((x, y) => expando[x.Key] = x.Value); foreach (var name in names) expando[name] = record[name]; yield return expando; } if (reader.IsClosed || !reader.NextResult()) break; } } conn.Close(); } } public IList ExecuteCrossDBQueries() { RunCrossDBQuery(databases, queries); return crossDBQueryResults; } public void RunCrossDBQuery(IEnumerable databases, Dictionary> sqlList) { var stopWatch = DateTime.Now; var query = databases.AsParallel() .SelectMany(database => sqlList.Where(sql => sql.Value.Any()).AsParallel() .Select(sql => new ThreadWithState(database, sql))); foreach (var q in query) { q.ThreadProc(); } var timer = DateTime.Now.Subtract(stopWatch).TotalSeconds; if (showStopWatch) timer.Dump(nameof(stopWatch)); } public static string BuildConnectionString(string server, string database, string username = null, string password = null) { return username == null ? $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;" : $"data source={server};initial catalog='{database}';User ID={username};pwd={password}"; } #endregion