[
  {
    "path": "LICENSE",
    "content": "Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "README.md",
    "content": "﻿sql-scripts\n===========\nRepo for sharing my SQL Server scripts and stored procedures. These have largely been tested on both Standard & Enterprise versions of SQL 2005, 2008, 2008R2, and 2012; you may need to tweak for 2014 and newer versions.\n\n# what's available\n\n## admin\n* dba_findWastedSpace_sp.sql\n  * Finds wasted space on a database and/or table\n* dba_recompile_sp.sql\n  * Recompiles all procs in a specific database or all procs; can recompile a specific table, too.\n* dba_replicationLatencyGet_sp.sql\n  * Retrieves the amount of replication latency in seconds\n* dba_replicationLatencyMonitor_sp.sql\n  * Stored procedure for retrieving & storing the amount of replication latency in seconds\n* sql-agent-job-history.sql\n  * Explores SQL Agent Job metadata to get job statuses — when the job last ran, when it will run again, an aggregate count of the number of successful and failed executions in the queried time period, T-SQL code to disable the job, etc.\n\n## dev\n* bcp_script_generator.sql\n  * Generates bcp scripts using SQL Server metadata\n* dba_parseString_udf.sql\n  * This function parses string input using a variable delimiter.\n* insert_statement_generator.sql\n  * Generates insert statements for Teradata using SQL Server metadata. This is useful for easily migrating small tables (i.e. < 1000 rows) from SQL Server to Teradata. DO NOT use on large tables. \n* teradata_ddl_generator.sql\n  * Generates Teradata DDL using SQL Server metadata\n  \n## indexes\n* dba_indexDefrag_sp.sql\n  * award-winning index defrag script\n* dba_indexLookup_sp.sql\n  * Retrieves index information for the specified table name.\n* dba_indexStats_sp.sql\n  * etrieves information regarding indexes; will return drop SQL statement for non-clustered indexes.\n* dba_missingIndexStoredProc_sp.sql\n  * Retrieves stored procedures with missing indexes in their cached query plans.\n* index_definition.sql\n  * Displays the definition of indexes; useful to audit indexes across servers & environments\n* missing.sql\n  * Displays potential missing indexes for a given database. Adding the indexes via the provided CREATE scripts may improve server performance. \n* unused.sql\n  *  Displays potential unused indexes for the current database. Dropping these indexes may improve database performance. These statistics are reset each time the server is rebooted, so make sure to review the [sqlserver_start_time] value to ensure the  statistics are captured for a meaningful time period.\n  \n## misc\n* dba_viewPageData_sp.sql\n  * Retrieves page data for the specified table/page.\n\n  \n# contributing\nContributions are welcome! To contribute a change or enhancement, please issue a pull request for me to review and merge. If you have any questions, I can be reached on Twitter @sqlfool. \n"
  },
  {
    "path": "admin/dba_findWastedSpace_sp.sql",
    "content": "If ObjectProperty(Object_ID('dbo.dba_findWastedSpace_sp'), N'IsProcedure') Is Null\nBegin\n    Execute ('Create Procedure dbo.dba_findWastedSpace_sp As Print ''Hello World!''')\n    RaisError('Procedure dba_findWastedSpace_sp created.', 10, 1);\nEnd;\nGo\n\nSet ANSI_Nulls On;\nSet Quoted_Identifier On;\nGo\n\nAlter Procedure dbo.dba_findWastedSpace_sp\n\n    /* Declare Parameters */\n      @databaseName     sysname     = 'AdventureWorks'\n    , @tableName        sysname     = 'Sales.SalesOrderDetail'\n    , @percentGrowth    tinyint     = 10    /* allow for up to 10% growth by default */\n    , @displayUnit      char(2)     = 'GB'  /* KB, MB, GB, or TB */\n    , @debug            bit         = 1\n\nAs\n/**********************************************************************************************************\n\n    NAME:           dba_findWastedSpace_sp\n\n    SYNOPSIS:       Finds wasted space on a database and/or table\n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2011-03-14\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n\n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20150619   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\nSet NoCount On;\nSet XACT_Abort On;\nSet Ansi_Padding On;\nSet Ansi_Warnings On;\nSet ArithAbort On;\nSet Concat_Null_Yields_Null On;\nSet Numeric_RoundAbort Off;\n\nBegin\n\n    /* Make sure our environment is clean and ready to go */\n    If Exists(Select object_id From tempdb.sys.tables Where name = '##values')\n        Drop Table ##values;\n\n    If Exists(Select object_id From tempdb.sys.tables Where name = '##definition')\n        Drop Table ##definition;\n\n    If Exists(Select object_id From tempdb.sys.tables Where name = '##spaceRequired')\n        Drop Table ##spaceRequired;\n\n    If Exists(Select object_id From tempdb.sys.tables Where name = '##results')\n        Drop Table ##results;\n\n    /* Declare Variables */\n    Declare @sqlStatement_getColumnList     nvarchar(max)\n        , @sqlStatement_values              nvarchar(max)\n        , @sqlStatement_columns             nvarchar(max)\n        , @sqlStatement_tableDefinition1    nvarchar(max)\n        , @sqlStatement_tableDefinition2    nvarchar(max)\n        , @sqlStatement_tableDefinition3    nvarchar(max)\n        , @sqlStatement_spaceRequired       nvarchar(max)\n        , @sqlStatement_results             nvarchar(max)\n        , @sqlStatement_displayResults      nvarchar(max)\n        , @sqlStatement_total               nvarchar(max)\n        , @currentRecord                    int\n        , @growthPercentage                 float;\n\n    Declare @columnList Table\n    (\n          id            int identity(1,1)\n        , table_id      int\n        , columnName    varchar(128)\n        , user_type_id  tinyint\n        , max_length    smallint\n        , columnStatus  tinyint\n    );\n\n    /* Initialize variables\n            I'm doing it this way to support 2005 environments, too */\n    Select @sqlStatement_tableDefinition1   = ''\n        , @sqlStatement_tableDefinition2    = ''\n        , @sqlStatement_tableDefinition3    = ''\n        , @sqlStatement_spaceRequired       = 'Select '\n        , @sqlStatement_results             = 'Select '\n        , @sqlStatement_displayResults      = ''\n        , @sqlStatement_total               = 'Select ''Total'', Null, '\n        , @sqlStatement_values              = 'Select '\n        , @sqlStatement_columns             = 'Select '\n        , @growthPercentage                 = 1+(@percentGrowth/100.0);\n\n    Set @sqlStatement_getColumnList = '\n    Select c.object_id As [table_id]\n        , c.name\n        , t.user_type_id\n        , c.max_length\n        , 0 /* not yet columnStatus */\n    From ' + @databaseName + '.sys.columns As c\n    Join ' + @databaseName + '.sys.types As t \n        On c.user_type_id = t.user_type_id\n    Where c.object_id = IsNull(Object_Id(''' + @databaseName + '.' + @tableName + '''), c.object_id)\n        And t.user_type_id In (48, 52, 56, 127, 167, 175, 231, 239);'\n\n    If @Debug = 1\n    Begin\n        Select @sqlStatement_getColumnList;\n    End;\n\n    Insert Into @columnList \n    Execute sp_executeSQL @sqlStatement_getColumnList;\n\n    If @Debug = 1\n    Begin\n        Select * From @columnList;\n    End;\n\n    /* Begin our loop.  We're going to run through this for every column.  */\n    While Exists(Select * From @columnList Where columnStatus = 0)\n    Begin\n\n        /* Grab a column that hasn't been processed yet */\n        Select Top 1 @currentRecord = id \n        From @columnList\n        Where columnStatus = 0\n        Order By id;\n\n        /* First, let's build the statement we're going to use to get our min/max values */\n        Select @sqlStatement_values = @sqlStatement_values + Case When user_type_id In (48, 52, 56, 127) \n                Then 'Max(' + columnName + ') As [' + columnName + '], ' \n                    + 'Min(' + columnName + ') As [min' + columnName + '], '\n                Else 'Max(Len(' + columnName + ')) As [' + columnName + '], ' \n                    + 'Avg(Len(' + columnName + ')) As [avg' + columnName + '], '\n                End \n        From @columnList\n        Where id = @currentRecord;\n\n        /* Next, let's build the statement that's going to show us how much space the column is currently consuming */\n        Select @sqlStatement_columns = @sqlStatement_columns \n            + Case  When user_type_id = 48  Then '1' -- tinyint\n                    When user_type_id = 52  Then '2' -- smallint\n                    When user_type_id = 56  Then '4' -- int\n                    When user_type_id = 127 Then '8' -- bigint\n                    When user_type_id In (167, 175) Then Cast(max_length As varchar(10))-- varchar or char\n                    Else Cast(max_length * 2 As varchar(10)) -- nvarchar or nchar\n                    --Else '0'\n                End + ' As [' + columnName + '], ' \n        From @columnList\n        Where id = @currentRecord;\n\n        /* This section is used to build a table definition */\n        Select @sqlStatement_tableDefinition1 = @sqlStatement_tableDefinition1 + '[' + columnName + '] ' \n            + Case  \n                When user_type_id = 48  Then 'tinyint'\n                When user_type_id = 52  Then 'smallint'\n                When user_type_id = 56  Then 'int'\n                When user_type_id = 127 Then 'bigint'\n                Else 'smallint'\n              End + ', ' \n            + Case When user_type_id In (48, 52, 56, 127) Then '[min' Else '[avg' End + columnName + '] '\n            + Case  \n                When user_type_id = 48  Then 'tinyint'\n                When user_type_id = 52  Then 'smallint'\n                When user_type_id = 56  Then 'int'\n                When user_type_id = 127 Then 'bigint'\n                Else 'smallint'\n              End + ', ' \n        From @columnList\n        Where id = @currentRecord;\n\n        /* More dynamic table definition code */\n        Select @sqlStatement_tableDefinition2 = @sqlStatement_tableDefinition2 + '[' + columnName + '] ' \n            + Case  \n                When user_type_id = 48  Then 'tinyint'\n                When user_type_id = 52  Then 'smallint'\n                When user_type_id = 56  Then 'int'\n                When user_type_id = 127 Then 'bigint'\n                Else 'smallint'\n              End + ', ' \n        From @columnList\n        Where id = @currentRecord;\n\n        /* And yet more dynamic table definition code */\n        Select @sqlStatement_tableDefinition3 = @sqlStatement_tableDefinition3 + columnName + ' smallint, '\n                                                    + columnName + '_bytes bigint, '\n        From @columnList\n        Where id = @currentRecord;\n\n        /* This is where we see how much space we actually need, based on our min/max values.\n           This is where we consider the % of growth that we expect to see in a reasonable period of time. */\n        Select @sqlStatement_spaceRequired = @sqlStatement_spaceRequired + \n            Case When user_type_id In (48, 52, 56, 127)\n                Then 'Case When ([' + columnName + '] * ' + Cast(@growthPercentage As varchar(5)) + ') <= 255 \n                                And [min' + columnName + '] >= 0 \n                                    Then 1\n                           When ([' + columnName + '] * ' + Cast(@growthPercentage As varchar(5)) + ') <= 32768 \n                                And [min' + columnName + '] >= -32768 \n                                    Then 2\n                           When ([' + columnName + '] * ' + Cast(@growthPercentage As varchar(5)) + ') <= 2147483647 \n                                And [min' + columnName + '] >= -2147483647 \n                                    Then 4\n                           Else 8 End '\n                Else columnName\n            End + ' As [' + columnName + '], '\n        From @columnList\n        Where id = @currentRecord;\n        \n        /* This is where the analysis occurs to tell us how much space we're potentially wasting */\n        Select @sqlStatement_results = @sqlStatement_results + \n            'd.[' + columnName + '] - sr.[' + columnName + '] As [' + columnName + '], ' +\n            '(d.[' + columnName + '] - sr.[' + columnName + ']) * rowCnt As [bytes], '\n        From @columnList\n        Where id = @currentRecord;\n\n        /* This is where we get our pretty results table from */\n        Select @sqlStatement_displayResults = @sqlStatement_displayResults + 'Select ''' + columnName + ''' As [columnName] '\n                                                + ', ' + columnName + ' As [byteReduction] '\n                                                -- + ', ' + columnName + '_bytes As [estimatedSpaceSavings] '\n                                                + ', ' + columnName + '_bytes / 1024.0 / 1024.0 As [estimatedSpaceSavings] '\n                                                + ' From ##results'\n                                                + ' Union All '\n        From @columnList\n        Where id = @currentRecord;\n\n        /* And lastly, this is where we get our total from */\n        Select @sqlStatement_total = @sqlStatement_total + '([' + columnName + '_bytes] / 1024.0 / 1024.0) + ' \n        From @columnList\n        Where id = @currentRecord;\n\n\n        /* Mark the column as processed so we can move on to the next one */\n        Update @columnList \n        Set columnStatus = 1\n        Where id = @currentRecord;\n\n    End;\n\n    Select @sqlStatement_values = @sqlStatement_values + ' Count(*) As [rowCnt], 1 As [id] From ' + @databaseName + '.' + @tableName + ' Option (MaxDop 1);'\n        , @sqlStatement_columns = @sqlStatement_columns + ' ' + Cast(@currentRecord As varchar(4)) + ' As [columnCnt], 1 As [id];';\n\n    Set @sqlStatement_tableDefinition1 = 'Create Table ##values(' \n                                        + @sqlStatement_tableDefinition1 \n                                        + ' rowCnt bigint, id tinyint)';\n\n    Set @sqlStatement_tableDefinition2 = 'Create Table ##definition(' \n                                        + @sqlStatement_tableDefinition2\n                                        + ' columnCnt bigint, id tinyint)';\n\n    Set @sqlStatement_tableDefinition3 = 'Create Table ##results(' \n                                        + @sqlStatement_tableDefinition3\n                                        + ' id tinyint)';\n\n    Set @sqlStatement_spaceRequired = @sqlStatement_spaceRequired + '1 As [id] Into ##spaceRequired From ##values;'\n\n    Set @sqlStatement_results = @sqlStatement_results + '1 As [id] From ##definition As d Join ##spaceRequired As sr On d.id = sr.id Join ##values As v On d.id = v.id;'\n\n    Set @sqlStatement_displayResults = @sqlStatement_displayResults + @sqlStatement_total + '0 From ##results';\n\n    /* Print our dynamic SQL statements in case we need to troubleshoot */\n    If @debug = 1\n    Begin\n        Select @sqlStatement_values As '@sqlStatement_values'\n            , @sqlStatement_columns As '@sqlStatement_columns'\n            , @sqlStatement_tableDefinition1 As '@sqlStatement_tableDefinition1'\n            , @sqlStatement_tableDefinition2 As '@sqlStatement_tableDefinition2'\n            , @sqlStatement_spaceRequired As '@sqlStatement_spaceRequired'\n            , @sqlStatement_results As '@sqlStatement_results'\n            , @sqlStatement_displayResults As '@sqlStatement_displayResults'\n            , @sqlStatement_total As '@sqlStatement_total';\n    End;\n\n    Select @sqlStatement_tableDefinition1 As 'Table Definition 1';\n    Execute sp_executeSQL @sqlStatement_tableDefinition1;\n\n    Select @sqlStatement_tableDefinition2 As 'Table Definition 2';\n    Execute sp_executeSQL @sqlStatement_tableDefinition2;\n\n    Select @sqlStatement_tableDefinition3 As 'Table Definition 3';\n    Execute sp_executeSQL @sqlStatement_tableDefinition3;\n\n    Select @sqlStatement_values As 'Insert 1';\n    Insert Into ##values \n    Execute sp_executeSQL @sqlStatement_values;\n\n    Select @sqlStatement_columns As 'Insert 2';\n    Insert Into ##definition \n    Execute sp_executeSQL @sqlStatement_columns;\n\n    Select @sqlStatement_spaceRequired As 'Execute space required';\n    Execute sp_executeSQL @sqlStatement_spaceRequired;\n\n    Select @sqlStatement_results As 'Execute results';\n    Insert Into ##results\n    Execute sp_executeSQL @sqlStatement_results;\n\n    /* Output our table values for troubleshooting purposes */\n    If @debug = 1\n    Begin\n        Select 'definition' As 'tableType', * From ##definition y \n        Select 'values' As 'tableType', * from ##values x \n        Select 'spaceRequired' As 'tableType', * From ##spaceRequired;\n        Select 'results' As 'tableType', * From ##results;\n    End;\n\n    Select @sqlStatement_displayResults As 'Final results';\n    Execute sp_executeSQL @sqlStatement_displayResults;\n\n    /* Clean up our mess */\n    --Drop Table ##values;\n    --Drop Table ##definition;\n    --Drop Table ##spaceRequired;\n    --Drop Table ##results;\n\n    Set NoCount Off;\n    Return 0;\nEnd\nGo\n\nSet Quoted_Identifier Off;\nGo"
  },
  {
    "path": "admin/dba_recompile_sp.sql",
    "content": "Use dbaTools;\nGo\n\nIf ObjectProperty(Object_ID('dbo.dba_recompile_sp'), N'IsProcedure') Is Null\nBegin\n    Execute ('Create Procedure dbo.dba_recompile_sp As Print ''Hello World!''')\n    RaisError('Procedure dba_recompile_sp created.', 10, 1);\nEnd;\nGo\n\nSet ANSI_Nulls On;\nSet Quoted_Identifier On;\nGo\n\nAlter Procedure dbo.dba_recompile_sp\n\n        /* Declare Parameters */\n          @databaseName nvarchar(128) = Null /* Null = all databases */\n        , @tableName    nvarchar(128) = Null /* Null = all tables */        \n\nAs\n/**********************************************************************************************************\n\n    NAME:           dba_recompile_sp\n\n    SYNOPSIS:       Recompiles all procs in a specific database or all procs; can recompile a specific table, too.\n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2009-09-12\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n\n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20150619   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\nSet NoCount On;\nSet XACT_Abort On;\nSet Ansi_Padding On;\nSet Ansi_Warnings On;\nSet ArithAbort On;\nSet Concat_Null_Yields_Null On;\nSet Numeric_RoundAbort Off;\n\nBegin\n\n    /* Make sure the global temp tables do not already exist, i.e. failed execution */\n    If Exists(Select * From tempdb.sys.tables Where name = '###databaseList')\n        Drop Table #databaseList;\n        \n    If Exists(Select * From tempdb.sys.tables Where name = '##tableList')\n        Drop Table tableList;\n\n    /* Declare Temp Tables */\n    Create Table ##databaseList\n    (\n          databaseName  nvarchar(128)\n        , processed     bit\n    );\n\n    Create Table ##tableList\n    (\n          databaseName  nvarchar(128)\n        , tableName     nvarchar(128)\n        , processed     bit\n    );\n\n    Insert Into ##databaseList\n    Select name As databaseName\n        , 0 As processed\n    From sys.databases\n    Where name = IsNull(@databaseName, name);\n    \n    While Exists(Select Top 1 databaseName From ##databaseList Where processed = 0)\n    Begin\n        \n        Execute sp_msforeachdb 'Use ?;\n            Select name As tableName\n            Into ##tableList\n            From sys.tables\n            Where name = IsNull(@tableName, name);\n\n            Declare @tableName nvarchar(128) = (Select Top 1 tableName From #tableList);\n\n            While Exists(Select Top 1 * From #tableList)\n            Begin\n                Execute sp_recompile @tableName;\n                Delete From #tableList Where tableName = @tableName;\n                Select Top 1 @tableName = tableName From #tableList Order By tableName;\n            End;\n\n            Drop Table ##tableList;'\n\n    End\n\n    Set NoCount Off;\n    Return 0;\nEnd\nGo\n\nSet Quoted_Identifier Off;\nGo\n\nIf ObjectProperty(Object_ID('dbo.dba_recompile_sp'), N'IsProcedure') = 1 \n    RaisError('Procedure dba_recompile_sp was successfully updated.', 10, 1);\nElse\n    RaisError('Procedure dba_recompile_sp FAILED to create!', 16, 1);\nGo"
  },
  {
    "path": "admin/dba_replicationLatencyGet_sp.sql",
    "content": "If ObjectProperty(Object_ID('dbo.dba_replicationLatencyGet_sp'), N'IsProcedure') = 1\nBegin\n    Drop Procedure dbo.dba_replicationLatencyGet_sp;\n    Print 'Procedure dba_replicationLatencyGet_sp dropped';\nEnd;\nGo\n\nSet Quoted_Identifier On\nGo\nSet ANSI_Nulls On\nGo\n\nCreate Procedure dbo.dba_replicationLatencyGet_sp\n\n        /* Declare Parameters */\n          @publicationToTest sysname        = N'goDaddyWebsiteTracking01'\n        , @replicationDelay  varchar(10)    = N'00:00:30'\n        , @iterations        int            = 5\n        , @iterationDelay    varchar(10)    = N'00:00:30'\n        , @deleteTokens      bit            = 1\n        , @deleteTempTable   bit            = 1\nAs\n/**********************************************************************************************************\n\n    NAME:           dba_replicationLatencyGet_sp\n\n    SYNOPSIS:       Retrieves the amount of replication latency in seconds\n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n                    \n    NOTES:          Default settings will run 1 test every minute for 5 minutes.\n\n                    @publicationToTest = defaults to goDaddyWebsiteTracking publication\n    \n                    @replicationDelay = how long to wait for the token to replicate;\n                        probably should not set to anything less than 10 (in seconds)\n    \n                    @iterations = how many tokens you want to test\n    \n                    @iterationDelay = how long to wait between sending test tokens\n                        (in seconds)\n    \n                    @deleteTokens = whether you want to retain tokens when done\n    \n                    @deleteTempTable = whether or not to retain the temporary table\n                        when done.  Data stored to ##tokenResults; set @deleteTempTable \n                        flag to 0 if you do not want to delete when done.\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2008-05-22\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n\n    USAGE:          EXEC dbo.dba_replicationLatencyGet_sp\n                      @publicationToTest    = N'your_publication'\n                    , @replicationDelay     = N'00:00:05'\n                    , @iterations           = 1\n                    , @iterationDelay       = N'00:00:05'\n                    , @deleteTokens         = 1\n                    , @deleteTempTable      = 1;\n\n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20150619   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\nSet NoCount On;\nSet XACT_Abort On;\n\nBegin\n\n    /* Declare Variables */\n    Declare @currentIteration   int\n          , @tokenID            bigint\n          , @currentDateTime    smalldatetime;\n\n    If Object_ID('tempdb.dbo.##tokenResults') Is Null\n    Begin\n        Create Table ##tokenResults\n                        ( iteration           int             Null\n                        , tracer_id           int             Null\n                        , distributor_latency int             Null\n                        , subscriber          varchar(1000)   Null\n                        , subscriber_db       varchar(1000)   Null\n                        , subscriber_latency  int             Null\n                        , overall_latency     int             Null );\n    End;\n\n    /* Initialize our variables */\n    Select @currentIteration = 0\n         , @currentDateTime  = GetDate();\n\n    While @currentIteration < @iterations\n    Begin\n\n        /* Insert a new tracer token in the publication database */\n        Execute sys.sp_postTracerToken \n          @publication = @publicationToTest,\n          @tracer_token_id = @tokenID OutPut;\n\n        /* Give a few seconds to allow the record to reach the subscriber */\n        WaitFor Delay @replicationDelay;\n\n        /* Store our results in a temp table for retrieval later */\n        Insert Into ##tokenResults\n        (\n            distributor_latency\n          , subscriber\n          , subscriber_db\n          , subscriber_latency\n          , overall_latency\n        )\n        Execute sys.sp_helpTracerTokenHistory @publicationToTest, @tokenID;\n\n        /* Assign the iteration and token id to the results for easier investigation */\n        Update ##tokenResults\n        Set iteration = @currentIteration + 1\n          , tracer_id = @tokenID\n        Where iteration Is Null;\n\n        /* Wait for the specified time period before creating another token */\n        WaitFor Delay @iterationDelay;\n\n        /* Avoid endless looping... :) */\n        Set @currentIteration = @currentIteration + 1;\n\n    End;\n\n    Select * From ##tokenResults;\n\n    If @deleteTempTable = 1\n    Begin\n        Drop Table ##tokenResults;\n    End;\n\n    If @deleteTokens = 1\n    Begin\n       Execute sp_deleteTracerTokenHistory @publication = @publicationToTest, @cutoff_date = @currentDateTime;\n    End;\n\n    Set NoCount Off;\n    Return 0;\nEnd\nGo\n\nSet Quoted_Identifier Off;\nGo\nSet ANSI_Nulls On;\nGo\n\nIf ObjectProperty(Object_ID('dbo.dba_replicationLatencyGet_sp'), N'IsProcedure') = 1 \n    RaisError('Procedure dba_replicationLatencyGet_sp was successfully created.', 10, 1);\nElse\n    RaisError('Procedure dba_replicationLatencyGet_sp FAILED to create!', 16, 1);\nGo\n"
  },
  {
    "path": "admin/dba_replicationLatencyMonitor_sp.sql",
    "content": "Use DBAHoldings;\nGo\n\nIf Object_ID('dbo.dba_replicationMonitor') Is Null\nBegin\n    Create Table dbo.dba_replicationMonitor\n    ( \n          monitor_id            int Identity(1,1)   Not Null\n        , monitorDate           smalldatetime       Not Null \n        , publicationName       sysname             Not Null\n        , publicationDB         sysname             Not Null\n        , iteration             int                 Null\n        , tracer_id             int                 Null\n        , distributor_latency   int                 Null\n        , subscriber            varchar(1000)       Null\n        , subscriber_db         varchar(1000)       Null\n        , subscriber_latency    int                 Null\n        , overall_latency       int                 Null \n    );\nEnd;\n\nIf ObjectProperty(Object_ID('dbo.dba_replicationLatencyMonitor_sp'), N'IsProcedure') = 1\nBegin\n    Drop Procedure dbo.dba_replicationLatencyMonitor_sp;\n    Print 'Procedure dba_replicationLatencyMonitor_sp dropped';\nEnd;\nGo\n\nSet Quoted_Identifier On\nGo\nSet ANSI_Nulls On\nGo\n\nCreate Procedure dbo.dba_replicationLatencyMonitor_sp\n\n        /* Declare Parameters */\n          @publicationToTest    sysname        = N'YourPublication01'\n        , @publicationDB        sysname        = N'YourPublicationDB'\n        , @replicationDelay     varchar(10)    = N'00:00:30'\n        , @iterations           int            = 5\n        , @iterationDelay       varchar(10)    = N'00:00:30'\n        , @displayResults       bit            = 0\n        , @deleteTokens         bit            = 1\nAs\n/**********************************************************************************************************\n\n    NAME:           dba_replicationLatencyMonitor_sp\n\n    SYNOPSIS:       Retrieves the amount of replication latency in seconds\n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n                    \n    NOTES:          Default settings will run 1 test every minute for 5 minutes.\n\n                      @publicationToTest = defaults to the specified publication\n                      \n                      @publicationDB = the database that is the source for the publication.\n      \t\t\t\t        The tracer procs are found in the publishing DB.\n      \n                      @replicationDelay = how long to wait for the token to replicate;\n                          probably should not set to anything less than 10 (in seconds)\n      \n                      @iterations = how many tokens you want to test\n      \n                      @iterationDelay = how long to wait between sending test tokens\n                          (in seconds)\n      \n                      @displayResults = print results to screen when complete\n      \n                      @deleteTokens = whether you want to retain tokens when done\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2008-11-23\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n\n    USAGE:          EXEC dbo.dba_replicationLatencyMonitor_sp\n                      @publicationToTest    = N'myTestPublication'\n                    , @publicationDB        = N'sandbox_publisher'\n                    , @replicationDelay     = N'00:00:05'\n                    , @iterations           = 1\n                    , @iterationDelay       = N'00:00:05'\n                    , @displayResults       = 1\n                    , @deleteTokens         = 1;\n\n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20150619   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\nSet NoCount On;\nSet XACT_Abort On;\n\nBegin\n\n    /* Declare Variables */\n    Declare @currentIteration   int\n          , @tokenID            bigint\n          , @currentDateTime    smalldatetime\n          , @sqlStatement       nvarchar(200)\n          , @parmDefinition\t\tnvarchar(500);\n\n    Declare @tokenResults Table\n    ( \n          iteration             int             Null\n        , tracer_id             int             Null\n        , distributor_latency   int             Null\n        , subscriber            varchar(1000)   Null\n        , subscriber_db         varchar(1000)   Null\n        , subscriber_latency    int             Null\n        , overall_latency       int             Null \n    );\n\n    /* Initialize our variables */\n    Select @currentIteration = 0\n         , @currentDateTime  = GetDate();\n\n    While @currentIteration < @iterations\n    Begin\n\n\t\t/* Prepare the stored procedure execution string */\n\t\tSet @sqlStatement = N'Execute ' + @publicationDB + N'.sys.sp_postTracerToken ' + \n\t\t\t\t\t\t\tN'@publication = @VARpublicationToTest , ' +\n\t\t\t\t\t\t\tN'@tracer_token_id = @VARtokenID OutPut;'\n\t\n\t\t/* Define the parameters used by the sp_ExecuteSQL later */\n\t\tSet @parmDefinition = N'@VARpublicationToTest sysname, ' +\n\t\t\tN'@VARtokenID bigint OutPut';\n\n        /* Insert a new tracer token in the publication database */\n        Execute sp_executesql \n              @sqlStatement\n            , @parmDefinition\n            , @VARpublicationToTest = @publicationToTest\n            , @VARtokenID = @TokenID OutPut;\n\n        /* Give a few seconds to allow the record to reach the subscriber */\n        WaitFor Delay @replicationDelay;\n        \n        /* Prepare our statement to retrieve tracer token data */\n        Select @sqlStatement = 'Execute ' + @publicationDB + '.sys.sp_helpTracerTokenHistory ' +\n                    N'@publication = @VARpublicationToTest , ' +\n                    N'@tracer_id = @VARtokenID'\n            , @parmDefinition = N'@VARpublicationToTest sysname, ' +\n                    N'@VARtokenID bigint';\n\n        /* Store our results for retrieval later */\n        Insert Into @tokenResults\n        (\n            distributor_latency\n          , subscriber\n          , subscriber_db\n          , subscriber_latency\n          , overall_latency\n        )\n        Execute sp_executesql \n              @sqlStatement\n            , @parmDefinition\n            , @VARpublicationToTest = @publicationToTest\n            , @VARtokenID = @TokenID;\n\n        /* Assign the iteration and token id to the results for easier investigation */\n        Update @tokenResults\n        Set iteration = @currentIteration + 1\n          , tracer_id = @tokenID\n        Where iteration Is Null;\n\n        /* Wait for the specified time period before creating another token */\n        WaitFor Delay @iterationDelay;\n\n        /* Avoid endless looping... :) */\n        Set @currentIteration = @currentIteration + 1;\n\n    End;\n\n    /* Display our results */\n    If @displayResults = 1\n    Begin\n        Select \n              iteration\n            , tracer_id\n            , IsNull(distributor_latency, 0) As 'distributor_latency'\n            , subscriber\n            , subscriber_db\n            , IsNull(subscriber_latency, 0) As 'subscriber_latency'\n            , IsNull(overall_latency, \n                IsNull(distributor_latency, 0) + IsNull(subscriber_latency, 0))\n                As 'overall_latency'\n        From @tokenResults;\n    End;\n\n    /* Store our results */\n    Insert Into dbo.dba_replicationMonitor\n    (\n          monitorDate\n        , publicationName\n        , publicationDB\n        , iteration\n        , tracer_id\n        , distributor_latency\n        , subscriber\n        , subscriber_db\n        , subscriber_latency\n        , overall_latency\n    )\n    Select \n          @currentDateTime\n        , @publicationToTest\n        , @publicationDB\n        , iteration\n        , tracer_id\n        , IsNull(distributor_latency, 0)\n        , subscriber\n        , subscriber_db\n        , IsNull(subscriber_latency, 0)\n        , IsNull(overall_latency, \n            IsNull(distributor_latency, 0) + IsNull(subscriber_latency, 0))\n    From @tokenResults;\n\n    /* Delete the tracer tokens if requested */\n    If @deleteTokens = 1\n    Begin\n    \n        Select @sqlStatement = 'Execute ' + @publicationDB + '.sys.sp_deleteTracerTokenHistory ' +\n                    N'@publication = @VARpublicationToTest , ' +\n                    N'@cutoff_date = @VARcurrentDateTime'\n            , @parmDefinition = N'@VARpublicationToTest sysname, ' +\n                    N'@VARcurrentDateTime datetime';\n\t        \n        Execute sp_executesql \n              @sqlStatement\n            , @parmDefinition\n            , @VARpublicationToTest = @publicationToTest\n            , @VARcurrentDateTime = @currentDateTime;\n    \n    End;\n\n    Set NoCount Off;\n    Return 0;\nEnd\nGo\n\nSet Quoted_Identifier Off;\nGo\nSet ANSI_Nulls On;\nGo\n\nIf ObjectProperty(Object_ID('dbo.dba_replicationLatencyMonitor_sp'), N'IsProcedure') = 1 \n    RaisError('Procedure dba_replicationLatencyMonitor_sp was successfully created.', 10, 1);\nElse\n    RaisError('Procedure dba_replicationLatencyMonitor_sp FAILED to create!', 16, 1);\nGo\n"
  },
  {
    "path": "admin/sql_agent_job_history.sql",
    "content": "/**********************************************************************************************************\n\n    NAME:           sql-agent-job-history.sql\n\n    SYNOPSIS:       Explores SQL Agent Job metadata to get job statuses — when the job last ran, when it\n                    will run again, an aggregate count of the number of successful and failed executions\n                    in the queried time period, T-SQL code to disable the job, etc.\n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n\n    CREATED:        2012-12-18\n\n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n\n    ----------------------------------------------------------------------------\n    DISCLAIMER:\n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied\n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20150619   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\nDECLARE @jobHistory TABLE\n(\n      job_id                UNIQUEIDENTIFIER\n    , success               INT\n    , cancel                INT\n    , fail                  INT\n    , retry                 INT\n    , last_execution_id     INT\n    , last_duration         CHAR(8)\n    , last_execution_start  DATETIME\n);\n\nWITH lastExecution\nAS\n(\n    SELECT job_id\n    , MAX(instance_id) AS last_instance_id\nFROM msdb.dbo.sysjobhistory\nWHERE step_id = 0\nGROUP BY job_id\n)\n\nINSERT INTO @jobHistory\nSELECT sjh.job_id\n    , SUM(CASE WHEN sjh.run_status = 1 AND step_id = 0 THEN 1 ELSE 0 END) AS success\n    , SUM(CASE WHEN sjh.run_status = 3 AND step_id = 0 THEN 1 ELSE 0 END) AS cancel\n    , SUM(CASE WHEN sjh.run_status = 0 AND step_id = 0 THEN 1 ELSE 0 END) AS fail\n    , SUM(CASE WHEN sjh.run_status = 2 THEN 1 ELSE 0 END) AS retry\n    , MAX(CASE WHEN sjh.step_id = 0 THEN instance_id ELSE NULL END) last_execution_id\n    , SUBSTRING(CAST(MAX(CASE WHEN le.job_id IS NOT NULL THEN sjh.run_duration ELSE NULL END) + 1000000 AS VARCHAR(7)),2,2) + ':'\n            + SUBSTRING(CAST(MAX(CASE WHEN le.job_id IS NOT NULL THEN sjh.run_duration ELSE NULL END) + 1000000 AS VARCHAR(7)),4,2) + ':'\n            + SUBSTRING(CAST(MAX(CASE WHEN le.job_id IS NOT NULL THEN sjh.run_duration ELSE NULL END) + 1000000 AS VARCHAR(7)),6,2)\n            AS last_duration\n    , MAX(CASE WHEN le.last_instance_id IS NOT NULL THEN\n        CONVERT(datetime, RTRIM(run_date))\n        + ((run_time / 10000 *  3600)\n        + ((run_time % 10000) / 100 * 60)\n        + (run_time  % 10000) % 100) / (86399.9964)\n      ELSE '1900-01-01' END) AS last_execution_start\nFROM msdb.dbo.sysjobhistory AS sjh\nLEFT JOIN lastExecution     AS le\n    ON sjh.job_id = le.job_id\n   AND sjh.instance_id = le.last_instance_id\nGROUP BY sjh.job_id;\n\n/* We need to parse the schedule into something we can understand */\nDECLARE @weekDay TABLE (\n      mask          INT\n    , maskValue     VARCHAR(32)\n);\n\nINSERT INTO @weekDay\nSELECT 1, 'Sunday'      UNION ALL\nSELECT 2, 'Monday'      UNION ALL\nSELECT 4, 'Tuesday'     UNION ALL\nSELECT 8, 'Wednesday'   UNION ALL\nSELECT 16, 'Thursday'   UNION ALL\nSELECT 32, 'Friday'     UNION ALL\nSELECT 64, 'Saturday';\n\n\n/* Now let's get our schedule information */\nWITH myCTE\nAS(\n    SELECT sched.name AS 'scheduleName'\n        , sched.schedule_id\n        , jobsched.job_id\n        , CASE\n            WHEN sched.freq_type = 1\n                THEN 'Once'\n            WHEN sched.freq_type = 4\n                AND sched.freq_interval = 1\n                    THEN 'Daily'\n            WHEN sched.freq_type = 4\n                THEN 'Every ' + CAST(sched.freq_interval AS VARCHAR(5)) + ' days'\n            WHEN sched.freq_type = 8 THEN\n                REPLACE( REPLACE( REPLACE((\n                    SELECT maskValue\n                    FROM @weekDay AS x\n                    WHERE sched.freq_interval & x.mask <> 0\n                    ORDER BY mask FOR XML RAW)\n                , '\"/><row maskValue=\"', ', '), '<row maskValue=\"', ''), '\"/>', '')\n                + CASE\n                    WHEN sched.freq_recurrence_factor <> 0\n                        AND sched.freq_recurrence_factor = 1\n                            THEN '; weekly'\n                    WHEN sched.freq_recurrence_factor <> 0\n                        THEN '; every '\n                + CAST(sched.freq_recurrence_factor AS VARCHAR(10)) + ' weeks' END\n            WHEN sched.freq_type = 16 THEN 'On day '\n                + CAST(sched.freq_interval AS VARCHAR(10)) + ' of every '\n                + CAST(sched.freq_recurrence_factor AS VARCHAR(10)) + ' months'\n            WHEN sched.freq_type = 32 THEN\n                CASE\n                    WHEN sched.freq_relative_interval = 1 THEN 'First'\n                    WHEN sched.freq_relative_interval = 2 THEN 'Second'\n                    WHEN sched.freq_relative_interval = 4 THEN 'Third'\n                    WHEN sched.freq_relative_interval = 8 THEN 'Fourth'\n                    WHEN sched.freq_relative_interval = 16 THEN 'Last'\n                END +\n                CASE\n                    WHEN sched.freq_interval = 1 THEN ' Sunday'\n                    WHEN sched.freq_interval = 2 THEN ' Monday'\n                    WHEN sched.freq_interval = 3 THEN ' Tuesday'\n                    WHEN sched.freq_interval = 4 THEN ' Wednesday'\n                    WHEN sched.freq_interval = 5 THEN ' Thursday'\n                    WHEN sched.freq_interval = 6 THEN ' Friday'\n                    WHEN sched.freq_interval = 7 THEN ' Saturday'\n                    WHEN sched.freq_interval = 8 THEN ' Day'\n                    WHEN sched.freq_interval = 9 THEN ' Weekday'\n                    WHEN sched.freq_interval = 10 THEN ' Weekend'\n                END\n                + CASE\n                    WHEN sched.freq_recurrence_factor <> 0\n                        AND sched.freq_recurrence_factor = 1\n                            THEN '; monthly'\n                    WHEN sched.freq_recurrence_factor <> 0\n                        THEN '; every '\n                + CAST(sched.freq_recurrence_factor AS VARCHAR(10)) + ' months'\n                  END\n            WHEN sched.freq_type = 64   THEN 'StartUp'\n            WHEN sched.freq_type = 128  THEN 'Idle'\n          END AS 'frequency'\n        , ISNULL('Every ' + CAST(sched.freq_subday_interval AS VARCHAR(10)) +\n            CASE\n                WHEN sched.freq_subday_type = 2 THEN ' seconds'\n                WHEN sched.freq_subday_type = 4 THEN ' minutes'\n                WHEN sched.freq_subday_type = 8 THEN ' hours'\n            END, 'Once') AS 'subFrequency'\n        , REPLICATE('0', 6 - LEN(sched.active_start_time))\n            + CAST(sched.active_start_time AS VARCHAR(6)) AS 'startTime'\n        , REPLICATE('0', 6 - LEN(sched.active_end_time))\n            + CAST(sched.active_end_time AS VARCHAR(6)) AS 'endTime'\n        , REPLICATE('0', 6 - LEN(jobsched.next_run_time))\n            + CAST(jobsched.next_run_time AS VARCHAR(6)) AS 'nextRunTime'\n        , CAST(jobsched.next_run_date AS CHAR(8)) AS 'nextRunDate'\n    FROM msdb.dbo.sysschedules      AS sched\n    JOIN msdb.dbo.sysjobschedules   AS jobsched\n        ON sched.schedule_id = jobsched.schedule_id\n    WHERE sched.enabled = 1\n)\n\n/* Finally, let's look at our actual jobs and tie it all together */\nSELECT CONVERT(NVARCHAR(128), SERVERPROPERTY('Servername'))             AS [serverName]\n    , job.job_id                                                        AS [jobID]\n    , job.name                                                          AS [jobName]\n    , CASE WHEN job.enabled = 1 THEN 'Enabled' ELSE 'Disabled' END      AS [jobStatus]\n    , COALESCE(sched.scheduleName, '(unscheduled)')                     AS [scheduleName]\n    , COALESCE(sched.frequency, '')                                     AS [frequency]\n    , COALESCE(sched.subFrequency, '')                                  AS [subFrequency]\n    , COALESCE(SUBSTRING(sched.startTime, 1, 2) + ':'\n        + SUBSTRING(sched.startTime, 3, 2) + ' - '\n        + SUBSTRING(sched.endTime, 1, 2) + ':'\n        + SUBSTRING(sched.endTime, 3, 2), '')                           AS [scheduleTime] -- HH:MM\n    , COALESCE(SUBSTRING(sched.nextRunDate, 1, 4) + '/'\n        + SUBSTRING(sched.nextRunDate, 5, 2) + '/'\n        + SUBSTRING(sched.nextRunDate, 7, 2) + ' '\n        + SUBSTRING(sched.nextRunTime, 1, 2) + ':'\n        + SUBSTRING(sched.nextRunTime, 3, 2), '')                       AS [nextRunDate]\n      /* Note: the sysjobschedules table refreshes every 20 min, so nextRunDate may be out of date */\n    , COALESCE(jh.success, 0)                                           AS [success]\n    , COALESCE(jh.cancel, 0)                                            AS [cancel]\n    , COALESCE(jh.fail, 0)                                              AS [fail]\n    , COALESCE(jh.retry, 0)                                             AS [retry]\n    , COALESCE(jh.last_execution_id, 0)                                 AS [lastExecutionID]\n    , jh.last_execution_start                                           AS [lastExecutionStart]\n    , COALESCE(jh.last_duration, '00:00:01')                            AS [lastDuration]\n    , 'EXECUTE msdb.dbo.sp_update_job @job_id = '''\n        + CAST(job.job_id AS CHAR(36)) + ''', @enabled = 0;'            AS [disableSQLScript]\nFROM msdb.dbo.sysjobs               AS job\nLEFT JOIN myCTE                     AS sched\n    ON job.job_id = sched.job_id\nLEFT JOIN @jobHistory               AS jh\n    ON job.job_id = jh.job_id\nWHERE job.enabled = 1 -- do not display disabled jobs\n    --AND jh.last_execution_start >= DATEADD(day, -1, GETDATE()) /* Pull just the last 24 hours */\nORDER BY nextRunDate;"
  },
  {
    "path": "dev/bcp_script_generator.sql",
    "content": "/**********************************************************************************************************\n\n    NAME:           bcp_script_generator.sql\n\n    SYNOPSIS:       Generates bcp scripts using SQL Server metadata\n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2012-05-17\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n\n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20150619   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\n-- User-defined variables --\n\nDECLARE @tableToBCP NVARCHAR(128)   = 'sandbox.dbo.example_table'\n    , @Top          VARCHAR(10)     = NULL -- Leave NULL for all rows\n    , @Delimiter    VARCHAR(4)      = '|'\n    , @UseNULL      BIT             = 1\n    , @OverrideChar CHAR(1)         = '~'\n    , @MaxDop       CHAR(1)         = '1'\n    , @Directory    VARCHAR(256)    = 'D:\\dba\\mufford\\scripts';\n\n\n-- Script-defined variables -- \n\nDECLARE @columnList TABLE (columnID INT);\n\nDECLARE @bcpStatement NVARCHAR(MAX) = 'BCP \"SELECT '\n    , @currentID INT\n    , @firstID INT;\n\nINSERT INTO @columnList\nSELECT column_id \nFROM sys.columns \nWHERE object_id = OBJECT_ID(@tableToBCP)\nORDER BY column_id;\n\nIF @Top IS NOT NULL\n    SET @bcpStatement = @bcpStatement + 'TOP (' + @Top + ') ';\n\nSELECT @firstID = MIN(columnID) FROM @columnList;\n\nWHILE EXISTS(SELECT * FROM @columnList)\nBEGIN\n\n    SELECT @currentID = MIN(columnID) FROM @columnList;\n\n    IF @currentID <> @firstID\n        SET @bcpStatement = @bcpStatement + ',';\n\n    SELECT @bcpStatement = @bcpStatement + \n                            CASE \n                                WHEN user_type_id IN (231, 167, 175, 239) \n                                THEN 'CASE WHEN ' + name + ' = '''' THEN ' \n                                    + CASE \n                                        WHEN is_nullable = 1 THEN 'NULL' \n                                        ELSE '''' + REPLICATE(@OverrideChar, max_length) + ''''\n                                      END\n                                    + ' WHEN ' + name + ' LIKE ''%' + @Delimiter + '%'''\n                                        + ' OR ' + name + ' LIKE ''%'' + CHAR(9) + ''%''' -- tab\n                                        + ' OR ' + name + ' LIKE ''%'' + CHAR(10) + ''%''' -- line feed\n                                        + ' OR ' + name + ' LIKE ''%'' + CHAR(13) + ''%''' -- carriage return\n                                        + ' THEN ' \n                                        + CASE \n                                            WHEN is_nullable = 1 THEN 'NULL' \n                                            ELSE '''' + REPLICATE(@OverrideChar, max_length) + ''''\n                                          END\n                                    + ' ELSE ' + name + ' END' \n                                ELSE name \n                            END \n    FROM sys.columns \n    WHERE object_id = OBJECT_ID(@tableToBCP)\n        AND column_id = @currentID;\n\n    DELETE FROM @columnList WHERE columnID = @currentID;\n\n\nEND;\n\nSET @bcpStatement = @bcpStatement + ' FROM ' + @tableToBCP \n    + ' WITH (NOLOCK) OPTION (MAXDOP 1);\" queryOut '\n    + @Directory + REPLACE(@tableToBCP, '.', '_') + '.dat -S' + @@SERVERNAME\n    + ' -T -t\"' + @Delimiter + '\" -c -C;'\n\nSELECT @bcpStatement;"
  },
  {
    "path": "dev/dba_parseString_udf.sql",
    "content": "\n/* Let's create our parsing function... */\nCREATE FUNCTION dbo.dba_parseString_udf\n(\n          @stringToParse VARCHAR(8000)  \n        , @delimiter     CHAR(1)\n)\nRETURNS @parsedString TABLE (stringValue VARCHAR(128))\nAS\n/*********************************************************************************\n    Name:       dba_parseString_udf\n \n    Author:     Michelle Ufford, http://sqlfool.com\n \n    Purpose:    This function parses string input using a variable delimiter.\n \n    Notes:      Two common delimiter values are space (' ') and comma (',')\n\n    Date        Initials    Description\n    ----------------------------------------------------------------------------\n    2011-05-20  MFU         Initial Release\n*********************************************************************************\nUsage: \t\t\n    SELECT *\n    FROM dba_parseString_udf(<string>, <delimiter>);\n\nTest Cases:\n\n    1.  multiple strings separated by space\n        SELECT * FROM dbo.dba_parseString_udf('  aaa  bbb  ccc ', ' ');\n\n    2.  multiple strings separated by comma\n        SELECT * FROM dbo.dba_parseString_udf(',aaa,bbb,,,ccc,', ',');\n*********************************************************************************/\nBEGIN\n\n    /* Declare variables */\n    DECLARE @trimmedString  VARCHAR(8000);\n\n    /* We need to trim our string input in case the user entered extra spaces */\n    SET @trimmedString = LTRIM(RTRIM(@stringToParse));\n\n    /* Let's create a recursive CTE to break down our string for us */\n    WITH parseCTE (StartPos, EndPos)\n    AS\n    (\n        SELECT 1 AS StartPos\n            , CHARINDEX(@delimiter, @trimmedString + @delimiter) AS EndPos\n        UNION ALL\n        SELECT EndPos + 1 AS StartPos\n            , CharIndex(@delimiter, @trimmedString + @delimiter , EndPos + 1) AS EndPos\n        FROM parseCTE\n        WHERE CHARINDEX(@delimiter, @trimmedString + @delimiter, EndPos + 1) <> 0\n    )\n\n    /* Let's take the results and stick it in a table */  \n    INSERT INTO @parsedString\n    SELECT SUBSTRING(@trimmedString, StartPos, EndPos - StartPos)\n    FROM parseCTE\n    WHERE LEN(LTRIM(RTRIM(SUBSTRING(@trimmedString, StartPos, EndPos - StartPos)))) > 0\n    OPTION (MaxRecursion 8000);\n\n    RETURN;   \nEND  "
  },
  {
    "path": "dev/insert_statement_generator.sql",
    "content": "/**********************************************************************************************************\n\n    NAME:           insert_statement_generator.sql\n\n    SYNOPSIS:       Generates insert statements for Teradata using SQL Server metadata.\n                    This is useful for easily migrating small tables (i.e. < 1000 rows) \n                    from SQL Server to Teradata. DO NOT use on large tables. \n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2012-07-26\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n\n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20150619   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\n-- User-defined variables --\nDECLARE \n      @tableName            NVARCHAR(128)   = 'dbo.example_table'\n    , @Top                  VARCHAR(10)     = 1000 -- Leave NULL for all rows\n    , @Execute              BIT             = 1\n    , @GenerateSchema       BIT             = 1\n    , @GenerateTruncate     BIT             = 1\n    , @TeradataDatabase     VARCHAR(30)     = 'mufford'\n    , @TeradataTable        VARCHAR(30)     = NULL -- Will generate if you leave NULL\n\n-- Script-defined variables -- \n\nDECLARE @columnList TABLE (columnID INT);\nDECLARE @TeradataTableName VARCHAR(60);\n\nIF @TeradataTable IS NULL\n    SET @TeradataTableName = @TeradataDatabase + '.tmp_' + SUBSTRING(@tableName,PATINDEX('%.%',@tableName)+1,26);\nELSE \n    SET @TeradataTableName = @TeradataDatabase + '.' + @TeradataTable;\n\nDECLARE @insertStatement    NVARCHAR(MAX) = '' --= 'SELECT '\n    , @columnStatement      NVARCHAR(MAX) = 'INSERT INTO ' + @TeradataTableName + ' ('\n    , @schemaStatement      NVARCHAR(MAX) = 'CREATE TABLE ' + @TeradataTableName + '('\n    , @currentID            INT\n    , @firstID              INT;\n\nINSERT INTO @columnList\nSELECT column_id \nFROM sys.columns \nWHERE object_id = OBJECT_ID(@tableName)\nORDER BY column_id;\n\nSELECT @firstID = MIN(columnID) FROM @columnList;\n\nWHILE EXISTS(SELECT * FROM @columnList)\nBEGIN\n\n    SELECT @currentID = MIN(columnID) FROM @columnList;\n\n    IF @currentID <> @firstID\n    BEGIN\n        SELECT \n              @columnStatement = @columnStatement + ','\n            , @schemaStatement = @schemaStatement + ','\n            , @insertStatement = @insertStatement + '+'',''+';\n    END\n\n    SELECT @columnStatement = @columnStatement + '\"' + SUBSTRING(name, 1, 30) + '\"'\n    FROM sys.columns\n    WHERE object_id = OBJECT_ID(@tableName)\n        AND column_id = @currentID;\n\n    SELECT @schemaStatement = @schemaStatement + '\"' + SUBSTRING(c.name, 1, 30) + '\" ' \n        + CASE \n            WHEN t.name = 'BIT'                             THEN 'BYTEINT'\n            WHEN t.name = 'TINYINT'                         THEN 'SMALLINT'\n            WHEN t.name = 'UNIQUEIDENTIFIER'                THEN 'CHAR(38)'\n            WHEN t.name = 'DATETIME'                        THEN 'TIMESTAMP(3)'\n            WHEN t.name = 'MONEY'                           THEN 'DECIMAL(18,4)'\n            WHEN t.name = 'XML'                             THEN 'CLOB'\n            WHEN t.name IN ('SMALLDATETIME', 'DATETIME2')   THEN 'TIMESTAMP(0)'\n            WHEN t.name IN ('NVARCHAR','NCHAR')\n                THEN SUBSTRING(t.name, 2, 10) + '(' + CAST(c.max_length / 2 AS VARCHAR(4)) + ') CHARACTER SET UNICODE NOT CASESPECIFIC'\n            WHEN t.name IN ('VARCHAR','CHAR')\n                THEN t.name + '(' + CAST(c.max_length AS VARCHAR(4)) + ')'\n            ELSE t.name\n        END\n        + CASE\n            WHEN c.is_nullable = 1 THEN ' NULL'\n            ELSE ' NOT NULL'\n        END\n    FROM sys.columns    AS c\n    JOIN sys.types      AS t\n        ON c.system_type_id = t.system_type_id\n    WHERE c.object_id = OBJECT_ID(@tableName)\n        AND c.column_id = @currentID;\n\n    SELECT DISTINCT @insertStatement = @insertStatement \n            + 'CASE WHEN ' + QUOTENAME(c.name) + ' IS NULL THEN ''NULL'' ELSE ' + \n            + CASE \n                WHEN t.name IN ('tinyint','smallint','int','real','float','bit','decimal','numeric','smallmoney','bigint') /* number-based columns */\n                    THEN 'CAST(' + QUOTENAME(c.name) + ' AS VARCHAR(' + CAST(c.precision AS VARCHAR(10)) + '))' \n                WHEN t.name IN ('datetime', 'date', 'datetime2', 'smalldatetime') /* date-based columns */\n                    THEN '''''''''+' + 'CONVERT(VARCHAR(23),' + QUOTENAME(c.name) + ',126)' + '+'''''''''\n                WHEN t.name IN ('uniqueidentifier') /* guid columns */\n                    THEN '''''''''+' + 'CAST(' + QUOTENAME(c.name) + ' AS CHAR(36))' + '+'''''''''\n                WHEN t.name IN ('XML') /* xml columns */\n                    THEN '''''''''+' + 'CAST(' + QUOTENAME(c.name) + ' AS VARCHAR(MAX))' + '+'''''''''\n                ELSE '''''''''+REPLACE(' + QUOTENAME(c.name) + ','''''''','''''''''''')+''''''''' --'''+''''''+''' /* character-based columns */\n              END \n                + ' END '\n    FROM sys.columns    AS c\n    JOIN sys.types      AS t\n        ON c.system_type_id = t.system_type_id\n    WHERE c.object_id = OBJECT_ID(@tableName)\n        AND c.column_id = @currentID;\n\n    DELETE FROM @columnList WHERE columnID = @currentID;\n\nEND;\n\nSET @insertStatement = 'SELECT ' + CASE WHEN @Top IS NOT NULL THEN 'TOP (' + @Top + ') ' ELSE '' END + '''' + @columnStatement + ') VALUES (''+' + @insertStatement + '+'');'' FROM ' + @tableName + ' WITH (NOLOCK);';\n\nIF @GenerateSchema = 1\n    SELECT @schemaStatement + ');' AS 'Execute this statement in Teradata to create the table:'\n\nIF @GenerateTruncate = 1\n    SELECT 'DELETE FROM ' + @TeradataTableName + ';' AS 'Execute this statement in Teradata to truncate the table:'\n\nIF @Execute = 1\n    EXECUTE sp_executeSQL @insertStatement;\nELSE\n    SELECT @insertStatement AS 'Execute this statement in SQL Server to generate commands:';\n"
  },
  {
    "path": "dev/teradata_ddl_generator.sql",
    "content": "/**********************************************************************************************************\n\n    NAME:           teradata_ddl_generator.sql\n\n    SYNOPSIS:       Generates Teradata DDL using SQL Server metadata\n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2012-05-17\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n    \n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20150619   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\n-- User-defined variables --\nDECLARE \n      @tableName            NVARCHAR(128)   = 'dbo.example_table'\n    , @TeradataDatabase     VARCHAR(30)     = 'mufford'\n    , @TeradataTable        VARCHAR(30)     = NULL -- Will generate if you leave NULL\n\n\n-- Script-defined variables -- \n\nDECLARE @columnList TABLE (columnID INT);\nDECLARE @TeradataTableName VARCHAR(60);\n\nIF @TeradataTable IS NULL\n    SET @TeradataTableName = @TeradataDatabase + '.tmp_' + SUBSTRING(@tableName,PATINDEX('%.%',@tableName)+1,26);\nELSE \n    SET @TeradataTableName = @TeradataDatabase + '.' + @TeradataTable;\n\nDECLARE \n      @schemaStatement      NVARCHAR(MAX) = 'CREATE TABLE ' + @TeradataTableName + '('\n    , @currentID            INT\n    , @firstID              INT;\n\nINSERT INTO @columnList\nSELECT column_id \nFROM sys.columns \nWHERE object_id = OBJECT_ID(@tableName)\nORDER BY column_id;\n\nSELECT @firstID = MIN(columnID) FROM @columnList;\n\nWHILE EXISTS(SELECT * FROM @columnList)\nBEGIN\n\n    SELECT @currentID = MIN(columnID) FROM @columnList;\n\n    IF @currentID <> @firstID\n    BEGIN\n        SELECT \n            @schemaStatement = @schemaStatement + ',';\n    END\n\n    SELECT @schemaStatement = @schemaStatement + '\"' + c.name + '\" ' \n        + CASE \n            WHEN t.name = 'BIT'                             THEN 'BYTEINT'\n            WHEN t.name = 'TINYINT'                         THEN 'SMALLINT'\n            WHEN t.name = 'UNIQUEIDENTIFIER'                THEN 'CHAR(38)'\n            WHEN t.name = 'DATETIME'                        THEN 'TIMESTAMP(3)'\n            WHEN t.name = 'MONEY'                           THEN 'DECIMAL(18,4)'\n            WHEN t.name = 'XML'                             THEN 'CLOB'\n            WHEN t.name IN ('SMALLDATETIME', 'DATETIME2')   THEN 'TIMESTAMP(0)'\n            WHEN t.name IN ('NVARCHAR','NCHAR')\n                THEN SUBSTRING(t.name, 2, 10) + '(' + CAST(c.max_length / 2 AS VARCHAR(4)) + ') CHARACTER SET UNICODE NOT CASESPECIFIC'\n            WHEN t.name IN ('VARCHAR','CHAR')\n                THEN t.name + '(' + CAST(c.max_length AS VARCHAR(4)) + ')'\n            ELSE t.name\n        END\n        + CASE\n            WHEN c.is_nullable = 1 THEN ' NULL'\n            ELSE ' NOT NULL'\n        END\n    FROM sys.columns    AS c\n    JOIN sys.types      AS t\n        ON c.system_type_id = t.system_type_id\n    WHERE c.object_id = OBJECT_ID(@tableName)\n        AND c.column_id = @currentID;\n\n    DELETE FROM @columnList WHERE columnID = @currentID;\n\nEND;\n\nSELECT @schemaStatement + ');' AS 'Execute this statement in Teradata to create the table:'"
  },
  {
    "path": "indexes/dba_indexDefrag_sp.sql",
    "content": "/*** Scroll down to the see important notes, disclaimers, and licensing information ***/\n\n/* Let's create our parsing function... */\nIF EXISTS ( SELECT  [object_id]\n            FROM    sys.objects\n            WHERE   name = 'dba_parseString_udf' )\n    DROP FUNCTION dbo.dba_parseString_udf;\nGO\n\nCREATE FUNCTION dbo.dba_parseString_udf\n(\n          @stringToParse VARCHAR(8000)  \n        , @delimiter     CHAR(1)\n)\nRETURNS @parsedString TABLE (stringValue VARCHAR(128))\nAS\n/*********************************************************************************\n    Name:       dba_parseString_udf\n \n    Author:     Michelle Ufford, http://sqlfool.com\n \n    Purpose:    This function parses string input using a variable delimiter.\n \n    Notes:      Two common delimiter values are space (' ') and comma (',')\n \n    Date        Initials    Description\n    ----------------------------------------------------------------------------\n    2011-05-20  MFU         Initial Release\n*********************************************************************************\nUsage: \t\t\n    SELECT *\n    FROM dba_parseString_udf(<string>, <delimiter>);\n \nTest Cases:\n \n    1.  multiple strings separated by space\n        SELECT * FROM dbo.dba_parseString_udf('  aaa  bbb  ccc ', ' ');\n \n    2.  multiple strings separated by comma\n        SELECT * FROM dbo.dba_parseString_udf(',aaa,bbb,,,ccc,', ',');\n*********************************************************************************/\nBEGIN\n \n    /* Declare variables */\n    DECLARE @trimmedString  VARCHAR(8000);\n \n    /* We need to trim our string input in case the user entered extra spaces */\n    SET @trimmedString = LTRIM(RTRIM(@stringToParse));\n \n    /* Let's create a recursive CTE to break down our string for us */\n    WITH parseCTE (StartPos, EndPos)\n    AS\n    (\n        SELECT 1 AS StartPos\n            , CHARINDEX(@delimiter, @trimmedString + @delimiter) AS EndPos\n        UNION ALL\n        SELECT EndPos + 1 AS StartPos\n            , CHARINDEX(@delimiter, @trimmedString + @delimiter , EndPos + 1) AS EndPos\n        FROM parseCTE\n        WHERE CHARINDEX(@delimiter, @trimmedString + @delimiter, EndPos + 1) <> 0\n    )\n \n    /* Let's take the results and stick it in a table */  \n    INSERT INTO @parsedString\n    SELECT SUBSTRING(@trimmedString, StartPos, EndPos - StartPos)\n    FROM parseCTE\n    WHERE LEN(LTRIM(RTRIM(SUBSTRING(@trimmedString, StartPos, EndPos - StartPos)))) > 0\n    OPTION (MaxRecursion 8000);\n \n    RETURN;   \nEND\nGO\n\n/* First, we need to take care of schema updates, in case you have a legacy \n   version of the script installed */\nDECLARE @indexDefragLog_rename      VARCHAR(128)\n  , @indexDefragExclusion_rename    VARCHAR(128)\n  , @indexDefragStatus_rename       VARCHAR(128);\n\nSELECT  @indexDefragLog_rename = 'dba_indexDefragLog_obsolete_' + CONVERT(VARCHAR(10), GETDATE(), 112)\n      , @indexDefragExclusion_rename = 'dba_indexDefragExclusion_obsolete_' + CONVERT(VARCHAR(10), GETDATE(), 112);\n\nIF EXISTS ( SELECT  [object_id]\n            FROM    sys.indexes\n            WHERE   name = 'PK_indexDefragLog' ) \n    EXECUTE sp_rename dba_indexDefragLog, @indexDefragLog_rename;\n\nIF EXISTS ( SELECT  [object_id]\n            FROM    sys.indexes\n            WHERE   name = 'PK_indexDefragExclusion' ) \n    EXECUTE sp_rename dba_indexDefragExclusion, @indexDefragExclusion_rename;\n\nIF NOT EXISTS ( SELECT  [object_id]\n                FROM    sys.indexes\n                WHERE   name = 'PK_indexDefragLog_v40' )\nBEGIN\n\n    CREATE TABLE dbo.dba_indexDefragLog\n    (\n         indexDefrag_id     INT IDENTITY(1, 1)  NOT NULL\n       , databaseID         INT                 NOT NULL\n       , databaseName       NVARCHAR(128)       NOT NULL\n       , objectID           INT                 NOT NULL\n       , objectName         NVARCHAR(128)       NOT NULL\n       , indexID            INT                 NOT NULL\n       , indexName          NVARCHAR(128)       NOT NULL\n       , partitionNumber    SMALLINT            NOT NULL\n       , fragmentation      FLOAT               NOT NULL\n       , page_count         INT                 NOT NULL\n       , dateTimeStart      DATETIME            NOT NULL\n       , dateTimeEnd        DATETIME            NULL\n       , durationSeconds    INT                 NULL\n       , sqlStatement       VARCHAR(4000)       NULL\n       , errorMessage       VARCHAR(1000)       NULL \n\n        CONSTRAINT PK_indexDefragLog_v40 \n            PRIMARY KEY CLUSTERED (indexDefrag_id)\n    );\n\n    PRINT 'dba_indexDefragLog Table Created';\n\nEND\n\nIF NOT EXISTS ( SELECT  [object_id]\n                FROM    sys.indexes\n                WHERE   name = 'PK_indexDefragExclusion_v40' )\nBEGIN\n\n    CREATE TABLE dbo.dba_indexDefragExclusion\n    (\n         databaseID         INT             NOT NULL\n       , databaseName       NVARCHAR(128)   NOT NULL\n       , objectID           INT             NOT NULL\n       , objectName         NVARCHAR(128)   NOT NULL\n       , indexID            INT             NOT NULL\n       , indexName          NVARCHAR(128)   NOT NULL\n       , exclusionMask      INT             NOT NULL\n            /* 1=Sunday, 2=Monday, 4=Tuesday, 8=Wednesday, 16=Thursday, 32=Friday, 64=Saturday */\n\n         CONSTRAINT PK_indexDefragExclusion_v40 \n            PRIMARY KEY CLUSTERED (databaseID, objectID, indexID)\n    );\n\n    PRINT 'dba_indexDefragExclusion Table Created';\n\nEND\n                \nIF NOT EXISTS ( SELECT  [object_id]\n                FROM    sys.indexes\n                WHERE   name = 'PK_indexDefragStatus_v40' )\nBEGIN\n\n    CREATE TABLE dbo.dba_indexDefragStatus\n    (\n         databaseID         INT             NOT NULL\n       , databaseName       NVARCHAR(128)   NOT NULL\n       , objectID           INT             NOT NULL\n       , indexID            INT             NOT NULL\n       , partitionNumber    SMALLINT        NOT NULL\n       , fragmentation      FLOAT           NOT NULL\n       , page_count         INT             NOT NULL\n       , range_scan_count   BIGINT          NOT NULL\n       , schemaName         NVARCHAR(128)   NULL\n       , objectName         NVARCHAR(128)   NULL\n       , indexName          NVARCHAR(128)   NULL\n       , scanDate           DATETIME        NOT NULL\n       , defragDate         DATETIME        NULL\n       , printStatus        BIT DEFAULT (0) NOT NULL\n       , exclusionMask      INT DEFAULT (0) NOT NULL\n    \n        CONSTRAINT PK_indexDefragStatus_v40 \n            PRIMARY KEY CLUSTERED (databaseID, objectID, indexID, partitionNumber)\n    );\n\n    PRINT 'dba_indexDefragStatus Table Created';\n\nEND;\n\nIF OBJECTPROPERTY(OBJECT_ID('dbo.dba_indexDefrag_sp'), N'IsProcedure') = 1 \n    BEGIN\n        DROP PROCEDURE dbo.dba_indexDefrag_sp;\n        PRINT 'Procedure dba_indexDefrag_sp dropped';\n    END;\nGo\n\nCREATE PROCEDURE dbo.dba_indexDefrag_sp\n\n    /* Declare Parameters */\n    @minFragmentation       FLOAT               = 10.0  \n        /* in percent, will not defrag if fragmentation less than specified */\n  , @rebuildThreshold       FLOAT               = 30.0  \n        /* in percent, greater than @rebuildThreshold will result in rebuild instead of reorg */\n  , @executeSQL             BIT                 = 1     \n        /* 1 = execute; 0 = print command only */\n  , @defragOrderColumn      NVARCHAR(20)        = 'range_scan_count'\n        /* Valid options are: range_scan_count, fragmentation, page_count */\n  , @defragSortOrder        NVARCHAR(4)         = 'DESC'\n        /* Valid options are: ASC, DESC */\n  , @timeLimit              INT                 = 720 /* defaulted to 12 hours */\n        /* Optional time limitation; expressed in minutes */\n  , @database               VARCHAR(128)        = NULL\n        /* Option to specify one or more database names, separated by commas; NULL will return all */\n  , @tableName              VARCHAR(4000)       = NULL  -- databaseName.schema.tableName\n        /* Option to specify a table name; null will return all */\n  , @forceRescan            BIT                 = 0\n        /* Whether or not to force a rescan of indexes; 1 = force, 0 = use existing scan, if available */\n  , @scanMode               VARCHAR(10)         = N'LIMITED'\n        /* Options are LIMITED, SAMPLED, and DETAILED */\n  , @minPageCount           INT                 = 8 \n        /*  MS recommends > 1 extent (8 pages) */\n  , @maxPageCount           INT                 = NULL\n        /* NULL = no limit */\n  , @excludeMaxPartition    BIT                 = 0\n        /* 1 = exclude right-most populated partition; 0 = do not exclude; see notes for caveats */\n  , @onlineRebuild          BIT                 = 1     \n        /* 1 = online rebuild; 0 = offline rebuild; only in Enterprise */\n  , @sortInTempDB           BIT                 = 1\n        /* 1 = perform sort operation in TempDB; 0 = perform sort operation in the index's database */\n  , @maxDopRestriction      TINYINT             = NULL\n        /* Option to restrict the number of processors for the operation; only in Enterprise */\n  , @printCommands          BIT                 = 0     \n        /* 1 = print commands; 0 = do not print commands */\n  , @printFragmentation     BIT                 = 0\n        /* 1 = print fragmentation prior to defrag; \n           0 = do not print */\n  , @defragDelay            CHAR(8)             = '00:00:05'\n        /* time to wait between defrag commands */\n  , @debugMode              BIT                 = 0\n        /* display some useful comments to help determine if/WHERE issues occur */\nAS /*********************************************************************************\n    Name:       dba_indexDefrag_sp\n\n    Author:     Michelle Ufford, http://sqlfool.com\n\n    Purpose:    Defrags one or more indexes for one or more databases\n\n    Notes:\n\n    CAUTION: TRANSACTION LOG SIZE SHOULD BE MONITORED CLOSELY WHEN DEFRAGMENTING.\n             DO NOT RUN UNATTENDED ON LARGE DATABASES DURING BUSINESS HOURS.\n\n      @minFragmentation     defaulted to 10%, will not defrag if fragmentation \n                            is less than that\n      \n      @rebuildThreshold     defaulted to 30% AS recommended by Microsoft in BOL;\n                            greater than 30% will result in rebuild instead\n\n      @executeSQL           1 = execute the SQL generated by this proc; \n                            0 = print command only\n\n      @defragOrderColumn    Defines how to prioritize the order of defrags.  Only\n                            used if @executeSQL = 1.  \n                            Valid options are: \n                            range_scan_count = count of range and table scans on the\n                                               index; in general, this is what benefits \n                                               the most FROM defragmentation\n                            fragmentation    = amount of fragmentation in the index;\n                                               the higher the number, the worse it is\n                            page_count       = number of pages in the index; affects\n                                               how long it takes to defrag an index\n\n      @defragSortOrder      The sort order of the ORDER BY clause.\n                            Valid options are ASC (ascending) or DESC (descending).\n\n      @timeLimit            Optional, limits how much time can be spent performing \n                            index defrags; expressed in minutes.\n\n                            NOTE: The time limit is checked BEFORE an index defrag\n                                  is begun, thus a long index defrag can exceed the\n                                  time limitation.\n\n      @database             Optional, specify specific database name to defrag;\n                            If not specified, all non-system databases will\n                            be defragged.\n\n      @tableName            Specify if you only want to defrag indexes for a \n                            specific table, format = databaseName.schema.tableName;\n                            if not specified, all tables will be defragged.\n\n      @forceRescan          Whether or not to force a rescan of indexes.  If set\n                            to 0, a rescan will not occur until all indexes have\n                            been defragged.  This can span multiple executions.\n                            1 = force a rescan\n                            0 = use previous scan, if there are indexes left to defrag\n\n      @scanMode             Specifies which scan mode to use to determine\n                            fragmentation levels.  Options are:\n                            LIMITED - scans the parent level; quickest mode,\n                                      recommended for most cases.\n                            SAMPLED - samples 1% of all data pages; if less than\n                                      10k pages, performs a DETAILED scan.\n                            DETAILED - scans all data pages.  Use great care with\n                                       this mode, AS it can cause performance issues.\n\n      @minPageCount         Specifies how many pages must exist in an index in order \n                            to be considered for a defrag.  Defaulted to 8 pages, AS \n                            Microsoft recommends only defragging indexes with more \n                            than 1 extent (8 pages).  \n\n                            NOTE: The @minPageCount will restrict the indexes that\n                            are stored in dba_indexDefragStatus table.\n\n      @maxPageCount         Specifies the maximum number of pages that can exist in \n                            an index and still be considered for a defrag.  Useful\n                            for scheduling small indexes during business hours and\n                            large indexes for non-business hours.\n\n                            NOTE: The @maxPageCount will restrict the indexes that\n                            are defragged during the current operation; it will not\n                            prevent indexes FROM being stored in the \n                            dba_indexDefragStatus table.  This way, a single scan\n                            can support multiple page count thresholds.\n\n      @excludeMaxPartition  If an index is partitioned, this option specifies whether\n                            to exclude the right-most populated partition.  Typically,\n                            this is the partition that is currently being written to in\n                            a sliding-window scenario.  Enabling this feature may reduce\n                            contention.  This may not be applicable in other types of \n                            partitioning scenarios.  Non-partitioned indexes are \n                            unaffected by this option.\n                            1 = exclude right-most populated partition\n                            0 = do not exclude\n\n      @onlineRebuild        1 = online rebuild; \n                            0 = offline rebuild\n\n      @sortInTempDB         Specifies whether to defrag the index in TEMPDB or in the\n                            database the index belongs to.  Enabling this option may\n                            result in faster defrags and prevent database file size \n                            inflation.\n                            1 = perform sort operation in TempDB\n                            0 = perform sort operation in the index's database \n\n      @maxDopRestriction    Option to specify a processor limit for index rebuilds\n\n      @printCommands        1 = print commands to screen; \n                            0 = do not print commands\n\n      @printFragmentation   1 = print fragmentation to screen;\n                            0 = do not print fragmentation\n\n      @defragDelay          Time to wait between defrag commands; gives the\n                            server a little time to catch up \n\n      @debugMode            1 = display debug comments; helps with troubleshooting\n                            0 = do not display debug comments\n\n    Called by:  SQL Agent Job or DBA\n\n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n    LICENSE: \n    This index defrag script is free to download and use for personal, educational, \n    and internal corporate purposes, provided that this header is preserved. \n    Redistribution or sale of this index defrag script, in whole or in part, is \n    prohibited without the author's express written consent.\n    ----------------------------------------------------------------------------\n    Date        Initials\tVersion Description\n    ----------------------------------------------------------------------------\n    2007-12-18  MFU         1.0     Initial Release\n    2008-10-17  MFU         1.1     Added @defragDelay, CIX_temp_indexDefragList\n    2008-11-17  MFU         1.2     Added page_count to log table\n                                    , added @printFragmentation option\n    2009-03-17  MFU         2.0     Provided support for centralized execution\n                                    , consolidated Enterprise & Standard versions\n                                    , added @debugMode, @maxDopRestriction\n                                    , modified LOB and partition logic  \n    2009-06-18  MFU         3.0     Fixed bug in LOB logic, added @scanMode option\n                                    , added support for stat rebuilds (@rebuildStats)\n                                    , support model and msdb defrag\n                                    , added columns to the dba_indexDefragLog table\n                                    , modified logging to show \"in progress\" defrags\n                                    , added defrag exclusion list (scheduling)\n    2009-08-28  MFU         3.1     Fixed read_only bug for database lists\n    2010-04-20  MFU         4.0     Added time limit option\n                                    , added static table with rescan logic\n                                    , added parameters for page count & SORT_IN_TEMPDB\n                                    , added try/catch logic and additional debug options\n                                    , added options for defrag prioritization\n                                    , fixed bug for indexes with allow_page_lock = off\n                                    , added option to exclude right-most partition\n                                    , removed @rebuildStats option\n                                    , refer to http://sqlfool.com for full release notes\n    2011-04-28  MFU         4.1     Bug fixes for databases requiring []\n                                    , cleaned up the create table section\n                                    , updated syntax for case-sensitive databases\n                                    , comma-delimited list for @database now supported\n*********************************************************************************\n    Example of how to call this script:\n\n        EXECUTE dbo.dba_indexDefrag_sp\n              @executeSQL           = 1\n            , @printCommands        = 1\n            , @debugMode            = 1\n            , @printFragmentation   = 1\n            , @forceRescan          = 1\n            , @maxDopRestriction    = 1\n            , @minPageCount         = 8\n            , @maxPageCount         = NULL\n            , @minFragmentation     = 1\n            , @rebuildThreshold     = 30\n            , @defragDelay          = '00:00:05'\n            , @defragOrderColumn    = 'page_count'\n            , @defragSortOrder      = 'DESC'\n            , @excludeMaxPartition  = 1\n            , @timeLimit            = NULL\n            , @database             = 'sandbox,sandbox_caseSensitive';\n*********************************************************************************/\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\nSET NOCOUNT ON;\nSET XACT_ABORT ON;\nSET QUOTED_IDENTIFIER ON;\n\nBEGIN\n\n    BEGIN TRY\n\n        /* Just a little validation... */\n        IF @minFragmentation IS NULL \n            OR @minFragmentation NOT BETWEEN 0.00 AND 100.0\n                SET @minFragmentation = 10.0;\n\n        IF @rebuildThreshold IS NULL\n            OR @rebuildThreshold NOT BETWEEN 0.00 AND 100.0\n                SET @rebuildThreshold = 30.0;\n\n        IF @defragDelay NOT LIKE '00:[0-5][0-9]:[0-5][0-9]'\n            SET @defragDelay = '00:00:05';\n\n        IF @defragOrderColumn IS NULL\n            OR @defragOrderColumn NOT IN ('range_scan_count', 'fragmentation', 'page_count')\n                SET @defragOrderColumn = 'range_scan_count';\n\n        IF @defragSortOrder IS NULL\n            OR @defragSortOrder NOT IN ('ASC', 'DESC')\n                SET @defragSortOrder = 'DESC';\n\n        IF @scanMode NOT IN ('LIMITED', 'SAMPLED', 'DETAILED')\n            SET @scanMode = 'LIMITED';\n\n        IF @executeSQL IS NULL\n            SET @executeSQL = 0;\n\n        IF @debugMode IS NULL\n            SET @debugMode = 0;\n\n        IF @forceRescan IS NULL\n            SET @forceRescan = 0;\n            \n        IF @minPageCount IS NULL\n            SET @minPageCount = 8;\n\n        IF @sortInTempDB IS NULL\n            SET @sortInTempDB = 1;\n\n        IF @onlineRebuild IS NULL\n            SET @onlineRebuild = 0;\n\n        IF @debugMode = 1 RAISERROR('Undusting the cogs AND starting up...', 0, 42) WITH NOWAIT;\n\n        /* Declare our variables */\n        DECLARE   @objectID                 INT\n                , @databaseID               INT\n                , @databaseName             NVARCHAR(128)\n                , @indexID                  INT\n                , @partitionCount           BIGINT\n                , @schemaName               NVARCHAR(128)\n                , @objectName               NVARCHAR(128)\n                , @indexName                NVARCHAR(128)\n                , @partitionNumber          SMALLINT\n                , @fragmentation            FLOAT\n                , @pageCount                INT\n                , @sqlCommand               NVARCHAR(4000)\n                , @rebuildCommand           NVARCHAR(200)\n                , @datetimestart            DATETIME\n                , @dateTimeEnd              DATETIME\n                , @containsLOB              BIT\n                , @editionCheck             BIT\n                , @debugMessage             NVARCHAR(4000)\n                , @updateSQL                NVARCHAR(4000)\n                , @partitionSQL             NVARCHAR(4000)\n                , @partitionSQL_Param       NVARCHAR(1000)\n                , @LOB_SQL                  NVARCHAR(4000)\n                , @LOB_SQL_Param            NVARCHAR(1000)\n                , @indexDefrag_id           INT\n                , @startdatetime            DATETIME\n                , @enddatetime              DATETIME\n                , @getIndexSQL              NVARCHAR(4000)\n                , @getIndexSQL_Param        NVARCHAR(4000)\n                , @allowPageLockSQL         NVARCHAR(4000)\n                , @allowPageLockSQL_Param   NVARCHAR(4000)\n                , @allowPageLocks           INT\n                , @excludeMaxPartitionSQL   NVARCHAR(4000);\n\n        /* Initialize our variables */\n        SELECT @startdatetime = GETDATE()\n            , @enddatetime = DATEADD(minute, @timeLimit, GETDATE());\n\n        /* Create our temporary tables */\n        CREATE TABLE #databaseList\n        (\n              databaseID        INT\n            , databaseName      VARCHAR(128)\n            , scanStatus        BIT\n        );\n\n        CREATE TABLE #processor \n        (\n              [index]           INT\n            , Name              VARCHAR(128)\n            , Internal_Value    INT\n            , Character_Value   INT\n        );\n\n        CREATE TABLE #maxPartitionList\n        (\n              databaseID        INT\n            , objectID          INT\n            , indexID           INT\n            , maxPartition      INT\n        );\n\n        IF @debugMode = 1 RAISERROR('Beginning validation...', 0, 42) WITH NOWAIT;\n\n        /* Make sure we're not exceeding the number of processors we have available */\n        INSERT INTO #processor\n        EXECUTE xp_msver 'ProcessorCount';\n\n        IF @maxDopRestriction IS NOT NULL AND @maxDopRestriction > (SELECT Internal_Value FROM #processor)\n            SELECT @maxDopRestriction = Internal_Value\n            FROM #processor;\n\n        /* Check our server version; 1804890536 = Enterprise, 610778273 = Enterprise Evaluation, -2117995310 = Developer */\n        IF (SELECT ServerProperty('EditionID')) IN (1804890536, 610778273, -2117995310) \n            SET @editionCheck = 1 -- supports online rebuilds\n        ELSE\n            SET @editionCheck = 0; -- does not support online rebuilds\n\n        /* Output the parameters we're working with */\n        IF @debugMode = 1 \n        BEGIN\n\n            SELECT @debugMessage = 'Your SELECTed parameters are... \n            Defrag indexes WITH fragmentation greater than ' + CAST(@minFragmentation AS VARCHAR(10)) + ';\n            REBUILD indexes WITH fragmentation greater than ' + CAST(@rebuildThreshold AS VARCHAR(10)) + ';\n            You' + CASE WHEN @executeSQL = 1 THEN ' DO' ELSE ' DO NOT' END + ' want the commands to be executed automatically; \n            You want to defrag indexes in ' + @defragSortOrder + ' order of the ' + UPPER(@defragOrderColumn) + ' value;\n            You have' + CASE WHEN @timeLimit IS NULL THEN ' NOT specified a time limit;' ELSE ' specified a time limit of ' \n                + CAST(@timeLimit AS VARCHAR(10)) END + ' minutes;\n            ' + CASE WHEN @database IS NULL THEN 'ALL databases' ELSE 'The ' + @database + ' database(s)' END + ' will be defragged;\n            ' + CASE WHEN @tableName IS NULL THEN 'ALL tables' ELSE 'The ' + @tableName + ' TABLE' END + ' will be defragged;\n            We' + CASE WHEN EXISTS(SELECT Top 1 * FROM dbo.dba_indexDefragStatus WHERE defragDate IS NULL)\n                AND @forceRescan <> 1 THEN ' WILL NOT' ELSE ' WILL' END + ' be rescanning indexes;\n            The scan will be performed in ' + @scanMode + ' mode;\n            You want to limit defrags to indexes with' + CASE WHEN @maxPageCount IS NULL THEN ' more than ' \n                + CAST(@minPageCount AS VARCHAR(10)) ELSE\n                ' BETWEEN ' + CAST(@minPageCount AS VARCHAR(10))\n                + ' AND ' + CAST(@maxPageCount AS VARCHAR(10)) END + ' pages;\n            Indexes will be defragged' + CASE WHEN @editionCheck = 0 OR @onlineRebuild = 0 THEN ' OFFLINE;' ELSE ' ONLINE;' END + '\n            Indexes will be sorted in' + CASE WHEN @sortInTempDB = 0 THEN ' the DATABASE' ELSE ' TEMPDB;' END + '\n            Defrag operations will utilize ' + CASE WHEN @editionCheck = 0 OR @maxDopRestriction IS NULL \n                THEN 'system defaults for processors;' \n                ELSE CAST(@maxDopRestriction AS VARCHAR(2)) + ' processors;' END + '\n            You' + CASE WHEN @printCommands = 1 THEN ' DO' ELSE ' DO NOT' END + ' want to PRINT the ALTER INDEX commands; \n            You' + CASE WHEN @printFragmentation = 1 THEN ' DO' ELSE ' DO NOT' END + ' want to OUTPUT fragmentation levels; \n            You want to wait ' + @defragDelay + ' (hh:mm:ss) BETWEEN defragging indexes;\n            You want to run in' + CASE WHEN @debugMode = 1 THEN ' DEBUG' ELSE ' SILENT' END + ' mode.';\n\n            RAISERROR(@debugMessage, 0, 42) WITH NOWAIT;\n        \n        END;\n\n        IF @debugMode = 1 RAISERROR('Grabbing a list of our databases...', 0, 42) WITH NOWAIT;\n\n        /* Retrieve the list of databases to investigate */\n        /* If @database is NULL, it means we want to defrag *all* databases */\n        IF @database IS NULL\n        BEGIN\n\n            INSERT INTO #databaseList\n            SELECT database_id\n                , name\n                , 0 -- not scanned yet for fragmentation\n            FROM sys.databases\n            WHERE [name] NOT IN ('master', 'tempdb')-- exclude system databases\n                AND [state] = 0 -- state must be ONLINE\n                AND is_read_only = 0;  -- cannot be read_only\n\n        END;\n        ELSE\n        /* Otherwise, we're going to just defrag our list of databases */\n        BEGIN\n\n            INSERT INTO #databaseList\n            SELECT database_id\n                , name\n                , 0 -- not scanned yet for fragmentation\n            FROM sys.databases AS d\n            JOIN dbo.dba_parseString_udf(@database, ',') AS x\n                ON d.name COLLATE database_default = x.stringValue\n            WHERE [name] NOT IN ('master', 'tempdb')-- exclude system databases\n                AND [state] = 0 -- state must be ONLINE\n                AND is_read_only = 0;  -- cannot be read_only\n\n        END; \n\n        /* Check to see IF we have indexes in need of defrag; otherwise, re-scan the database(s) */\n        IF NOT EXISTS(SELECT Top 1 * FROM dbo.dba_indexDefragStatus WHERE defragDate IS NULL)\n            OR @forceRescan = 1\n        BEGIN\n\n            /* Truncate our list of indexes to prepare for a new scan */\n            TRUNCATE TABLE dbo.dba_indexDefragStatus;\n\n            IF @debugMode = 1 RAISERROR('Looping through our list of databases and checking for fragmentation...', 0, 42) WITH NOWAIT;\n\n            /* Loop through our list of databases */\n            WHILE (SELECT COUNT(*) FROM #databaseList WHERE scanStatus = 0) > 0\n            BEGIN\n\n                SELECT Top 1 @databaseID = databaseID\n                FROM #databaseList\n                WHERE scanStatus = 0;\n\n                SELECT @debugMessage = '  working on ' + DB_NAME(@databaseID) + '...';\n\n                IF @debugMode = 1\n                    RAISERROR(@debugMessage, 0, 42) WITH NOWAIT;\n\n               /* Determine which indexes to defrag using our user-defined parameters */\n                INSERT INTO dbo.dba_indexDefragStatus\n                (\n                      databaseID\n                    , databaseName\n                    , objectID\n                    , indexID\n                    , partitionNumber\n                    , fragmentation\n                    , page_count\n                    , range_scan_count\n                    , scanDate\n                )\n                SELECT\n                      ps.database_id AS 'databaseID'\n                    , QUOTENAME(DB_NAME(ps.database_id)) AS 'databaseName'\n                    , ps.[object_id] AS 'objectID'\n                    , ps.index_id AS 'indexID'\n                    , ps.partition_number AS 'partitionNumber'\n                    , SUM(ps.avg_fragmentation_in_percent) AS 'fragmentation'\n                    , SUM(ps.page_count) AS 'page_count'\n                    , os.range_scan_count\n                    , GETDATE() AS 'scanDate'\n                FROM sys.dm_db_index_physical_stats(@databaseID, OBJECT_ID(@tableName), NULL , NULL, @scanMode) AS ps\n                JOIN sys.dm_db_index_operational_stats(@databaseID, OBJECT_ID(@tableName), NULL , NULL) AS os\n                    ON ps.database_id = os.database_id\n                    AND ps.[object_id] = os.[object_id]\n                    AND ps.index_id = os.index_id\n                    AND ps.partition_number = os.partition_number\n                WHERE avg_fragmentation_in_percent >= @minFragmentation \n                    AND ps.index_id > 0 -- ignore heaps\n                    AND ps.page_count > @minPageCount \n                    AND ps.index_level = 0 -- leaf-level nodes only, supports @scanMode\n                GROUP BY ps.database_id \n                    , QUOTENAME(DB_NAME(ps.database_id)) \n                    , ps.[object_id]\n                    , ps.index_id \n                    , ps.partition_number \n                    , os.range_scan_count\n                OPTION (MAXDOP 2);\n\n                /* Do we want to exclude right-most populated partition of our partitioned indexes? */\n                IF @excludeMaxPartition = 1\n                BEGIN\n\n                    SET @excludeMaxPartitionSQL = '\n                        SELECT ' + CAST(@databaseID AS VARCHAR(10)) + ' AS [databaseID]\n                            , [object_id]\n                            , index_id\n                            , MAX(partition_number) AS [maxPartition]\n                        FROM [' + DB_NAME(@databaseID) + '].sys.partitions\n                        WHERE partition_number > 1\n                            AND [rows] > 0\n                        GROUP BY object_id\n                            , index_id;';\n\n                    INSERT INTO #maxPartitionList\n                    EXECUTE sp_executesql @excludeMaxPartitionSQL;\n\n                END;\n                \n                /* Keep track of which databases have already been scanned */\n                UPDATE #databaseList\n                SET scanStatus = 1\n                WHERE databaseID = @databaseID;\n\n            END\n\n            /* We don't want to defrag the right-most populated partition, so\n               delete any records for partitioned indexes where partition = MAX(partition) */\n            IF @excludeMaxPartition = 1\n            BEGIN\n\n                DELETE ids\n                FROM dbo.dba_indexDefragStatus AS ids\n                JOIN #maxPartitionList AS mpl\n                    ON ids.databaseID = mpl.databaseID\n                    AND ids.objectID = mpl.objectID\n                    AND ids.indexID = mpl.indexID\n                    AND ids.partitionNumber = mpl.maxPartition;\n\n            END;\n\n            /* Update our exclusion mask for any index that has a restriction ON the days it can be defragged */\n            UPDATE ids\n            SET ids.exclusionMask = ide.exclusionMask\n            FROM dbo.dba_indexDefragStatus AS ids\n            JOIN dbo.dba_indexDefragExclusion AS ide\n                ON ids.databaseID = ide.databaseID\n                AND ids.objectID = ide.objectID\n                AND ids.indexID = ide.indexID;\n         \n        END\n\n        SELECT @debugMessage = 'Looping through our list... there are ' + CAST(COUNT(*) AS VARCHAR(10)) + ' indexes to defrag!'\n        FROM dbo.dba_indexDefragStatus\n        WHERE defragDate IS NULL\n            AND page_count BETWEEN @minPageCount AND ISNULL(@maxPageCount, page_count);\n\n        IF @debugMode = 1 RAISERROR(@debugMessage, 0, 42) WITH NOWAIT;\n\n        /* Begin our loop for defragging */\n        WHILE (SELECT COUNT(*) \n               FROM dbo.dba_indexDefragStatus \n               WHERE (\n                           (@executeSQL = 1 AND defragDate IS NULL) \n                        OR (@executeSQL = 0 AND defragDate IS NULL AND printStatus = 0)\n                     )\n                AND exclusionMask & POWER(2, DATEPART(weekday, GETDATE())-1) = 0\n                AND page_count BETWEEN @minPageCount AND ISNULL(@maxPageCount, page_count)) > 0\n        BEGIN\n\n            /* Check to see IF we need to exit our loop because of our time limit */        \n            IF ISNULL(@enddatetime, GETDATE()) < GETDATE()\n            BEGIN\n                RAISERROR('Our time limit has been exceeded!', 11, 42) WITH NOWAIT;\n            END;\n\n            IF @debugMode = 1 RAISERROR('  Picking an index to beat into shape...', 0, 42) WITH NOWAIT;\n\n            /* Grab the index with the highest priority, based on the values submitted; \n               Look at the exclusion mask to ensure it can be defragged today */\n            SET @getIndexSQL = N'\n            SELECT TOP 1 \n                  @objectID_Out         = objectID\n                , @indexID_Out          = indexID\n                , @databaseID_Out       = databaseID\n                , @databaseName_Out     = databaseName\n                , @fragmentation_Out    = fragmentation\n                , @partitionNumber_Out  = partitionNumber\n                , @pageCount_Out        = page_count\n            FROM dbo.dba_indexDefragStatus\n            WHERE defragDate IS NULL ' \n                + CASE WHEN @executeSQL = 0 THEN 'AND printStatus = 0' ELSE '' END + '\n                AND exclusionMask & Power(2, DatePart(weekday, GETDATE())-1) = 0\n                AND page_count BETWEEN @p_minPageCount AND ISNULL(@p_maxPageCount, page_count)\n            ORDER BY + ' + @defragOrderColumn + ' ' + @defragSortOrder;\n                       \n            SET @getIndexSQL_Param = N'@objectID_Out        INT OUTPUT\n                                     , @indexID_Out         INT OUTPUT\n                                     , @databaseID_Out      INT OUTPUT\n                                     , @databaseName_Out    NVARCHAR(128) OUTPUT\n                                     , @fragmentation_Out   INT OUTPUT\n                                     , @partitionNumber_Out INT OUTPUT\n                                     , @pageCount_Out       INT OUTPUT\n                                     , @p_minPageCount      INT\n                                     , @p_maxPageCount      INT';\n\n            EXECUTE sp_executesql @getIndexSQL\n                , @getIndexSQL_Param\n                , @p_minPageCount       = @minPageCount\n                , @p_maxPageCount       = @maxPageCount\n                , @objectID_Out         = @objectID         OUTPUT\n                , @indexID_Out          = @indexID          OUTPUT\n                , @databaseID_Out       = @databaseID       OUTPUT\n                , @databaseName_Out     = @databaseName     OUTPUT\n                , @fragmentation_Out    = @fragmentation    OUTPUT\n                , @partitionNumber_Out  = @partitionNumber  OUTPUT\n                , @pageCount_Out        = @pageCount        OUTPUT;\n\n            IF @debugMode = 1 RAISERROR('  Looking up the specifics for our index...', 0, 42) WITH NOWAIT;\n\n            /* Look up index information */\n            SELECT @updateSQL = N'UPDATE ids\n                SET schemaName = QUOTENAME(s.name)\n                    , objectName = QUOTENAME(o.name)\n                    , indexName = QUOTENAME(i.name)\n                FROM dbo.dba_indexDefragStatus AS ids\n                INNER JOIN ' + @databaseName + '.sys.objects AS o\n                    ON ids.objectID = o.[object_id]\n                INNER JOIN ' + @databaseName + '.sys.indexes AS i\n                    ON o.[object_id] = i.[object_id]\n                    AND ids.indexID = i.index_id\n                INNER JOIN ' + @databaseName + '.sys.schemas AS s\n                    ON o.schema_id = s.schema_id\n                WHERE o.[object_id] = ' + CAST(@objectID AS VARCHAR(10)) + '\n                    AND i.index_id = ' + CAST(@indexID AS VARCHAR(10)) + '\n                    AND i.type > 0\n                    AND ids.databaseID = ' + CAST(@databaseID AS VARCHAR(10));\n\n            EXECUTE sp_executesql @updateSQL;\n\n            /* Grab our object names */\n            SELECT @objectName  = objectName\n                , @schemaName   = schemaName\n                , @indexName    = indexName\n            FROM dbo.dba_indexDefragStatus\n            WHERE objectID = @objectID\n                AND indexID = @indexID\n                AND databaseID = @databaseID;\n\n            IF @debugMode = 1 RAISERROR('  Grabbing the partition COUNT...', 0, 42) WITH NOWAIT;\n\n            /* Determine if the index is partitioned */\n            SELECT @partitionSQL = 'SELECT @partitionCount_OUT = COUNT(*)\n                                        FROM ' + @databaseName + '.sys.partitions\n                                        WHERE object_id = ' + CAST(@objectID AS VARCHAR(10)) + '\n                                            AND index_id = ' + CAST(@indexID AS VARCHAR(10)) + ';'\n                , @partitionSQL_Param = '@partitionCount_OUT INT OUTPUT';\n\n            EXECUTE sp_executesql @partitionSQL, @partitionSQL_Param, @partitionCount_OUT = @partitionCount OUTPUT;\n\n            IF @debugMode = 1 RAISERROR('  Seeing IF there are any LOBs to be handled...', 0, 42) WITH NOWAIT;\n        \n            /* Determine if the table contains LOBs */\n            SELECT @LOB_SQL = ' SELECT @containsLOB_OUT = COUNT(*)\n                                FROM ' + @databaseName + '.sys.columns WITH (NoLock) \n                                WHERE [object_id] = ' + CAST(@objectID AS VARCHAR(10)) + '\n                                   AND (system_type_id IN (34, 35, 99)\n                                            OR max_length = -1);'\n                                /*  system_type_id --> 34 = IMAGE, 35 = TEXT, 99 = NTEXT\n                                    max_length = -1 --> VARBINARY(MAX), VARCHAR(MAX), NVARCHAR(MAX), XML */\n                    , @LOB_SQL_Param = '@containsLOB_OUT INT OUTPUT';\n\n            EXECUTE sp_executesql @LOB_SQL, @LOB_SQL_Param, @containsLOB_OUT = @containsLOB OUTPUT;\n\n            IF @debugMode = 1 RAISERROR('  Checking for indexes that do NOT allow page locks...', 0, 42) WITH NOWAIT;\n\n            /* Determine if page locks are allowed; for those indexes, we need to always REBUILD */\n            SELECT @allowPageLockSQL = 'SELECT @allowPageLocks_OUT = COUNT(*)\n                                        FROM ' + @databaseName + '.sys.indexes\n                                        WHERE object_id = ' + CAST(@objectID AS VARCHAR(10)) + '\n                                            AND index_id = ' + CAST(@indexID AS VARCHAR(10)) + '\n                                            AND Allow_Page_Locks = 0;'\n                , @allowPageLockSQL_Param = '@allowPageLocks_OUT INT OUTPUT';\n\n            EXECUTE sp_executesql @allowPageLockSQL, @allowPageLockSQL_Param, @allowPageLocks_OUT = @allowPageLocks OUTPUT;\n\n            IF @debugMode = 1 RAISERROR('  Building our SQL statements...', 0, 42) WITH NOWAIT;\n\n            /* IF there's not a lot of fragmentation, or if we have a LOB, we should REORGANIZE */\n            IF (@fragmentation < @rebuildThreshold OR @containsLOB >= 1 OR @partitionCount > 1)\n                AND @allowPageLocks = 0\n            BEGIN\n            \n                SET @sqlCommand = N'ALTER INDEX ' + @indexName + N' ON ' + @databaseName + N'.' \n                                    + @schemaName + N'.' + @objectName + N' REORGANIZE';\n\n                /* If our index is partitioned, we should always REORGANIZE */\n                IF @partitionCount > 1\n                    SET @sqlCommand = @sqlCommand + N' PARTITION = ' \n                                    + CAST(@partitionNumber AS NVARCHAR(10));\n\n            END\n            /* If the index is heavily fragmented and doesn't contain any partitions or LOB's, \n               or if the index does not allow page locks, REBUILD it */\n            ELSE IF (@fragmentation >= @rebuildThreshold OR @allowPageLocks <> 0)\n                AND ISNULL(@containsLOB, 0) != 1 AND @partitionCount <= 1\n            BEGIN\n\n                /* Set online REBUILD options; requires Enterprise Edition */\n                IF @onlineRebuild = 1 AND @editionCheck = 1 \n                    SET @rebuildCommand = N' REBUILD WITH (ONLINE = ON';\n                ELSE\n                    SET @rebuildCommand = N' REBUILD WITH (ONLINE = Off';\n                \n                /* Set sort operation preferences */\n                IF @sortInTempDB = 1 \n                    SET @rebuildCommand = @rebuildCommand + N', SORT_IN_TEMPDB = ON';\n                ELSE\n                    SET @rebuildCommand = @rebuildCommand + N', SORT_IN_TEMPDB = Off';\n\n                /* Set processor restriction options; requires Enterprise Edition */\n                IF @maxDopRestriction IS NOT NULL AND @editionCheck = 1\n                    SET @rebuildCommand = @rebuildCommand + N', MAXDOP = ' + CAST(@maxDopRestriction AS VARCHAR(2)) + N')';\n                ELSE\n                    SET @rebuildCommand = @rebuildCommand + N')';\n\n                SET @sqlCommand = N'ALTER INDEX ' + @indexName + N' ON ' + @databaseName + N'.'\n                                + @schemaName + N'.' + @objectName + @rebuildCommand;\n\n            END\n            ELSE\n                /* Print an error message if any indexes happen to not meet the criteria above */\n                IF @printCommands = 1 OR @debugMode = 1\n                    RAISERROR('We are unable to defrag this index.', 0, 42) WITH NOWAIT;\n\n            /* Are we executing the SQL?  IF so, do it */\n            IF @executeSQL = 1\n            BEGIN\n\n                SET @debugMessage = 'Executing: ' + @sqlCommand;\n                \n                /* Print the commands we're executing if specified to do so */\n                IF @printCommands = 1 OR @debugMode = 1\n                    RAISERROR(@debugMessage, 0, 42) WITH NOWAIT;\n\n                /* Grab the time for logging purposes */\n                SET @datetimestart  = GETDATE();\n\n                /* Log our actions */\n                INSERT INTO dbo.dba_indexDefragLog\n                (\n                      databaseID\n                    , databaseName\n                    , objectID\n                    , objectName\n                    , indexID\n                    , indexName\n                    , partitionNumber\n                    , fragmentation\n                    , page_count\n                    , dateTimeStart\n                    , sqlStatement\n                )\n                SELECT\n                      @databaseID\n                    , @databaseName\n                    , @objectID\n                    , @objectName\n                    , @indexID\n                    , @indexName\n                    , @partitionNumber\n                    , @fragmentation\n                    , @pageCount\n                    , @datetimestart\n                    , @sqlCommand;\n\n                SET @indexDefrag_id = SCOPE_IDENTITY();\n\n                /* Wrap our execution attempt in a TRY/CATCH and log any errors that occur */\n                BEGIN TRY\n\n                    /* Execute our defrag! */\n                    EXECUTE sp_executesql @sqlCommand;\n                    SET @dateTimeEnd = GETDATE();\n                    \n                    /* Update our log with our completion time */\n                    UPDATE dbo.dba_indexDefragLog\n                    SET dateTimeEnd = @dateTimeEnd\n                        , durationSeconds = DATEDIFF(second, @datetimestart, @dateTimeEnd)\n                    WHERE indexDefrag_id = @indexDefrag_id;\n\n                END TRY\n                BEGIN CATCH\n\n                    /* Update our log with our error message */\n                    UPDATE dbo.dba_indexDefragLog\n                    SET dateTimeEnd = GETDATE()\n                        , durationSeconds = -1\n                        , errorMessage = ERROR_MESSAGE()\n                    WHERE indexDefrag_id = @indexDefrag_id;\n\n                    IF @debugMode = 1 \n                        RAISERROR('  An error has occurred executing this command! Please review the dba_indexDefragLog table for details.'\n                            , 0, 42) WITH NOWAIT;\n\n                END CATCH\n\n                /* Just a little breather for the server */\n                WAITFOR DELAY @defragDelay;\n\n                UPDATE dbo.dba_indexDefragStatus\n                SET defragDate = GETDATE()\n                    , printStatus = 1\n                WHERE databaseID       = @databaseID\n                  AND objectID         = @objectID\n                  AND indexID          = @indexID\n                  AND partitionNumber  = @partitionNumber;\n\n            END\n            ELSE\n            /* Looks like we're not executing, just printing the commands */\n            BEGIN\n                IF @debugMode = 1 RAISERROR('  Printing SQL statements...', 0, 42) WITH NOWAIT;\n                \n                IF @printCommands = 1 OR @debugMode = 1 \n                    PRINT ISNULL(@sqlCommand, 'error!');\n\n                UPDATE dbo.dba_indexDefragStatus\n                SET printStatus = 1\n                WHERE databaseID       = @databaseID\n                  AND objectID         = @objectID\n                  AND indexID          = @indexID\n                  AND partitionNumber  = @partitionNumber;\n            END\n\n        END\n\n        /* Do we want to output our fragmentation results? */\n        IF @printFragmentation = 1\n        BEGIN\n\n            IF @debugMode = 1 RAISERROR('  Displaying a summary of our action...', 0, 42) WITH NOWAIT;\n\n            SELECT databaseID\n                , databaseName\n                , objectID\n                , objectName\n                , indexID\n                , indexName\n                , partitionNumber\n                , fragmentation\n                , page_count\n                , range_scan_count\n            FROM dbo.dba_indexDefragStatus\n            WHERE defragDate >= @startdatetime\n            ORDER BY defragDate;\n\n        END;\n\n    END TRY\n    BEGIN CATCH\n\n        SET @debugMessage = ERROR_MESSAGE() + ' (Line Number: ' + CAST(ERROR_LINE() AS VARCHAR(10)) + ')';\n        PRINT @debugMessage;\n\n    END CATCH;\n\n    /* When everything is said and done, make sure to get rid of our temp table */\n    DROP TABLE #databaseList;\n    DROP TABLE #processor;\n    DROP TABLE #maxPartitionList;\n\n    IF @debugMode = 1 RAISERROR('DONE!  Thank you for taking care of your indexes!  :)', 0, 42) WITH NOWAIT;\n\n    SET NOCOUNT OFF;\n    RETURN 0;\nEND\n"
  },
  {
    "path": "indexes/dba_indexLookup_sp.sql",
    "content": "If ObjectProperty(Object_ID('dbo.dba_indexLookup_sp'), N'IsProcedure') Is Null\nBegin\n    Execute ('Create Procedure dbo.dba_indexLookup_sp As Print ''Hello World!''')\n    RaisError('Procedure dbo.dba_indexLookup_sp created.', 10, 1);\nEnd;\nGo\n\nSet ANSI_Nulls On;\nSet Ansi_Padding On;\nSet Ansi_Warnings On;\nSet ArithAbort On;\nSet Concat_Null_Yields_Null On;\nSet NoCount On;\nSet Numeric_RoundAbort Off;\nSet Quoted_Identifier On;\nGo\n\nAlter Procedure dbo.dba_indexLookup_sp\n\n        /* Declare Parameters */\n        @tableName  varchar(128)  =  Null\nAs\n/**********************************************************************************************************\n\n    NAME:           dba_indexLookup_sp\n\n    SYNOPSIS:       Retrieves index information for the specified table name.\n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n\n    NOTES:          If the tableName is left null, it will return index information \n                    for all tables and indexes.\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2008-10-28\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n\n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20150619   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\nSet NoCount On;\nSet XACT_Abort On;\n\nBegin\n\n    Declare @objectID int;\n\n    If @tableName Is Not Null\n        Set @objectID = Object_ID(@tableName);\n\n    With indexCTE(partition_scheme_name\n                , partition_function_name\n                , data_space_id)\n    As (\n        Select sps.name\n            , spf.name\n            , sps.data_space_id\n        From sys.partition_schemes As sps\n        Join sys.partition_functions As spf\n            On sps.function_id = spf.function_id\n    )\n\n    Select st.name As 'table_name'\n        , IsNull(ix.name, '') As 'index_name'\n        , ix.object_id\n        , ix.index_id\n\t\t, Cast(\n            Case When ix.index_id = 1 \n                    Then 'clustered' \n                When ix.index_id =0\n                    Then 'heap'\n                Else 'nonclustered' End\n\t\t\t+ Case When ix.ignore_dup_key <> 0 \n                Then ', ignore duplicate keys' \n                    Else '' End\n\t\t\t+ Case When ix.is_unique <> 0 \n                Then ', unique' \n                    Else '' End\n\t\t\t+ Case When ix.is_primary_key <> 0 \n                Then ', primary key' Else '' End As varchar(210)\n            ) As 'index_description'\n        , IsNull(Replace( Replace( Replace(\n            (   \n                Select c.name As 'columnName'\n                From sys.index_columns As sic\n                Join sys.columns As c \n                    On c.column_id = sic.column_id \n                    And c.object_id = sic.object_id\n                Where sic.object_id = ix.object_id\n                    And sic.index_id = ix.index_id\n                    And is_included_column = 0\n                Order By sic.index_column_id\n                For XML Raw)\n                , '\"/><row columnName=\"', ', ')\n                , '<row columnName=\"', '')\n                , '\"/>', ''), '')\n            As 'indexed_columns'\n        , IsNull(Replace( Replace( Replace(\n            (   \n                Select c.name As 'columnName'\n                From sys.index_columns As sic\n                Join sys.columns As c \n                    On c.column_id = sic.column_id \n                    And c.object_id = sic.object_id\n                Where sic.object_id = ix.object_id\n                    And sic.index_id = ix.index_id\n                    And is_included_column = 1\n                Order By sic.index_column_id\n                For XML Raw)\n                , '\"/><row columnName=\"', ', ')\n                , '<row columnName=\"', '')\n                , '\"/>', ''), '')\n            As 'included_columns'\n        , IsNull(cte.partition_scheme_name, '') As 'partition_scheme_name'\n        , Count(partition_number) As 'partition_count'\n        , Sum(rows) As 'row_count'\n    From sys.indexes As ix\n    Join sys.partitions As sp\n        On ix.object_id = sp.object_id\n        And ix.index_id = sp.index_id\n    Join sys.tables As st\n        On ix.object_id = st.object_id\n    Left Join indexCTE As cte\n        On ix.data_space_id = cte.data_space_id\n    Where ix.object_id = IsNull(@objectID, ix.object_id)\n    Group By st.name\n        , IsNull(ix.name, '')\n        , ix.object_id\n        , ix.index_id\n\t\t, Cast(\n            Case When ix.index_id = 1 \n                    Then 'clustered' \n                When ix.index_id =0\n                    Then 'heap'\n                Else 'nonclustered' End\n\t\t\t+ Case When ix.ignore_dup_key <> 0 \n                Then ', ignore duplicate keys' \n                    Else '' End\n\t\t\t+ Case When ix.is_unique <> 0 \n                Then ', unique' \n                    Else '' End\n\t\t\t+ Case When ix.is_primary_key <> 0 \n                Then ', primary key' Else '' End As varchar(210)\n            )\n        , IsNull(cte.partition_scheme_name, '')\n        , IsNull(cte.partition_function_name, '')\n    Order By table_name\n        , index_id;\n\n    Set NoCount Off;\n    Return 0;\nEnd\nGo\n\nSet Quoted_Identifier Off;\nGo\n"
  },
  {
    "path": "indexes/dba_indexStats_sp.sql",
    "content": "If ObjectProperty(Object_ID('dbo.dba_indexStats_sp'), N'IsProcedure') = 1\nBegin\n    Drop Procedure dbo.dba_indexStats_sp;\n    Print 'Procedure dba_indexStats_sp dropped';\nEnd;\nGo\n\nSet Quoted_Identifier On\nGo\nSet ANSI_Nulls On\nGo\n\nCreate Procedure dbo.dba_indexStats_sp\n\n        /* Declare Parameters */\n          @databaseName         varchar(256)    = Null\n        , @indexType            varchar(256)    = Null\n        , @minRowCount          int             = Null\n        , @maxRowCount          int             = Null\n        , @minSeekScanLookup    int             = Null\n        , @maxSeekScanLookup    int             = Null\nAs\n/**********************************************************************************************************\n\n    NAME:           dba_indexStats_sp\n\n    SYNOPSIS:       Retrieves information regarding indexes; will return drop SQL\n                    statement for non-clustered indexes.\n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n\n    NOTES:          @databaseName - optional, specify a specific database to interrogate;\n                    by default, all user databases will be returned\n\n                    @indexType - optional, valid options are: \n                                    Clustered\n                                    NonClustered\n                                    Unique Clustered\n                                    Unique NonClustered\n                                    Heap\n    \n                    @minRowCount - optional, specify a minimum number of rows an index\n                                    must cover\n    \n                    @maxRowCount - optional, specify a maximum number of rows an index\n                                    must cover\n    \n                    @minSeekScanLookup - optional, min sum aggregation of index scans, \n                                    seeks, and look-ups.  Useful for finding unused indexes\n    \n                    @minSeekScanLookup - optional, max sum aggregation of index scans,  \n                                    seeks, and look-ups.  Useful for finding unused indexes\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2008-07-11\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n    \n    USAGE:          EXEC dbo.dba_indexStats_sp\n                      @databaseName         = 'your_db'\n                    , @indexType            = 'NonClustered'\n                    , @minSeekScanLookup    = 0\n                    , @maxSeekScanLookup    = 1000\n                    , @minRowCount          = 0\n                    , @maxRowCount          = 10000000;\n\n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20150619   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\nSet NoCount On;\nSet XACT_Abort On;\n\nBegin\n\n    /* Declare Variables */\n        Create Table #indexStats \n        (\n              databaseName          varchar(256)\n            , objectName            varchar(256)\n            , indexName             varchar(256)\n            , indexType             varchar(256)\n            , user_seeks            int\n            , user_scans            int\n            , user_lookups          int\n            , user_updates          int\n            , total_seekScanLookup  int\n            , rowCounts             int\n            , SQL_DropStatement     varchar(2000)\n        );\n\n    /* Check for existing transactions;\n       If one exists, exit with error. */\n    If @@TranCount > 0 \n    Begin\n\n        /* Log the fact that there were open transactions */\n        Execute dbo.dba_logError_sp @errorType = 'app'\n            , @app_errorProcedure = 'dba_indexStats_sp'\n            , @app_errorMessage = 'Open transaction exists; dba_indexStats_sp proc will not execute.';\n          Print 'Open transactions exist!';\n\n    End\n    Else\n    Begin\n        Begin Try\n\n        Execute sp_MSForEachDB 'Use [?]\n\n        Declare @dbid int\n            , @dbName varchar(100);\n\n        Select @dbid = DB_ID()\n            , @dbName = DB_Name();\n\n        With indexSizeCTE (object_id, index_id, rowCounts) As\n        (\n            Select [object_id]\n                , index_id\n                , Sum([rows]) As ''rowCounts''\n            From sys.partitions\n            Group By [object_id]\n                , index_id\n        ) \n\n        Insert Into #indexStats\n        Select  \n                  @dbName\n                , Object_Name(ix.[object_id]) as objectName\n                , ix.name As ''indexName''\n                , Case \n                    When ix.is_unique = 1 \n                        Then ''UNIQUE ''\n                    Else ''''\n                  End + ix.type_desc As ''indexType''\n                , ddius.user_seeks\n                , ddius.user_scans\n                , ddius.user_lookups\n                , ddius.user_updates\n                , ddius.user_seeks + ddius.user_scans + ddius.user_lookups\n                , isc.rowCounts\n                , Case \n                    When ix.type = 2 And ix.is_unique = 0\n                        Then ''Drop Index '' + ix.name + '' On '' + @dbName + ''.dbo.'' + Object_Name(ddius.[object_id]) + '';''\n                    When ix.type = 2 And ix.is_unique = 1\n                        Then ''Alter Table '' + @dbName + ''.dbo.'' + Object_Name(ddius.[object_ID]) + '' Drop Constraint '' + ix.name + '';''\n                    Else '' ''\n                  End As ''SQL_DropStatement''\n        From sys.indexes As ix\n            Left Outer Join sys.dm_db_index_usage_stats ddius\n                On ix.object_id = ddius.object_id\n                    And ix.index_id = ddius.index_id\n            Left Outer Join indexSizeCTE As isc\n                On ix.object_id = isc.object_id\n                    And ix.index_id = isc.index_id\n        Where ddius.database_id = @dbid\n            And ObjectProperty(ix.[object_id], N''IsUserTable'') = 1\n        Order By (ddius.user_seeks + ddius.user_scans + ddius.user_lookups) Asc;\n        '\n\n        Select databaseName\n            , objectName\n            , indexName\n            , indexType\n            , user_seeks\n            , user_scans\n            , user_lookups\n            , total_seekScanLookup\n            , user_updates\n            , rowCounts\n            , SQL_DropStatement\n        From #indexStats\n        Where databaseName = IsNull(@databaseName, databaseName)\n          And indexType = IsNull(@indexType, indexType)\n          And rowCounts Between IsNull(@minRowCount, rowCounts) And IsNull(@maxRowCount, rowCounts)\n          And total_seekScanLookup Between IsNull(@minSeekScanLookup, total_seekScanLookup) And IsNull(@maxSeekScanLookup, total_seekScanLookup)\n          And databaseName Not In ('master', 'msdb', 'tempdb', 'model')\n        Order By total_seekScanLookup;\n\n        End Try\n        Begin Catch\n\n            /* Return an error message and log it */\n              Execute dbo.dba_logError_sp;\n              Print 'An error has occurred!';\n\n        End Catch;\n    End;\n\n    /* Clean up! */\n    Drop Table #indexStats;\n\n    Set NoCount Off;\n    Return 0;\nEnd\nGo\n\nSet Quoted_Identifier Off;\nGo\nSet ANSI_Nulls On;\nGo\n\nIf ObjectProperty(Object_ID('dbo.dba_indexStats_sp'), N'IsProcedure') = 1 \n    RaisError('Procedure dba_indexStats_sp was successfully created.', 10, 1);\nElse\n    RaisError('Procedure dba_indexStats_sp FAILED to create!', 16, 1);\nGo"
  },
  {
    "path": "indexes/dba_missingIndexStoredProc_sp.sql",
    "content": "Use dbaTools;\nGo\n\n/* Create a stored procedure skeleton */\nIf ObjectProperty(Object_ID('dbo.dba_missingIndexStoredProc_sp'), N'IsProcedure') Is Null\nBegin\n    Execute ('Create Procedure dbo.dba_missingIndexStoredProc_sp As Print ''Hello World!''')\n    RaisError('Procedure dba_missingIndexStoredProc_sp created.', 10, 1);\nEnd;\nGo\n\n/* Drop our table if it already exists */\nIf Exists(Select Object_ID From sys.tables Where [name] = N'dba_missingIndexStoredProc')\nBegin\n    Drop Table dbo.dba_missingIndexStoredProc\n    Print 'dba_missingIndexStoredProc table dropped!';\nEnd\n\n/* Create our table */\nCreate Table dbo.dba_missingIndexStoredProc\n(\n      missingIndexSP_id     int Identity(1,1)   Not Null\n    , databaseName          varchar(128)        Not Null\n    , databaseID            int                 Not Null\n    , objectName            varchar(128)        Not Null\n    , objectID              int                 Not Null\n    , query_plan            xml                 Not Null\n    , executionDate         smalldatetime       Not Null\n    , statementExecutions   int                 Not Null\n    \n    Constraint PK_missingIndexStoredProc\n        Primary Key Clustered(missingIndexSP_id)\n);\n\nPrint 'dba_missingIndexStoredProc Table Created';\n\n/* Configure our settings */\nSet ANSI_Nulls On;\nSet Quoted_Identifier On;\nGo\n\nAlter Procedure dbo.dba_missingIndexStoredProc_sp\n\n        /* Declare Parameters */\n            @lastExecuted_inDays    int = 7\n          , @minExecutionCount      int = 1\n          , @logResults             bit = 1\n          , @displayResults         bit = 0\n\nAs\n/**********************************************************************************************************\n\n    NAME:           dba_missingIndexStoredProc_sp\n\n    SYNOPSIS:       Retrieves stored procedures with missing indexes in their cached query plans.\n                \n                    @lastExecuted_inDays = number of days old the cached query plan\n                                       can be to still appear in the results;\n                                       the HIGHER the number, the longer the\n                                       execution time.\n\n                    @minExecutionCount = minimum number of executions the cached\n                                     query plan can have to still appear \n                                     in the results; the LOWER the number,\n                                     the longer the execution time.\n\n                    @logResults = store results in dba_missingIndexStoredProc\n                \n                    @displayResults = return results to the caller\n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n\n    NOTES:          This is not 100% guaranteed to catch all missing indexes in\n                    a stored procedure.  It will only catch it if the stored proc's\n                    query plan is still in cache.  Run regularly to help minimize\n                    the chance of missing a proc.\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2009-09-03\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n    \n    USAGE:          Exec dbo.dba_missingIndexStoredProc_sp\n                      @lastExecuted_inDays  = 30\n                    , @minExecutionCount    = 5\n                    , @logResults           = 1\n                    , @displayResults       = 1;\n\n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20150619   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\nSet NoCount On;\nSet XACT_Abort On;\nSet Ansi_Padding On;\nSet Ansi_Warnings On;\nSet ArithAbort On;\nSet Concat_Null_Yields_Null On;\nSet Numeric_RoundAbort Off;\n\nBegin\n\n    /* Declare Variables */\n    Declare @currentDateTime smalldatetime;\n\n    Set @currentDateTime = GetDate();\n\n    Declare @plan_handles Table\n    (\n          plan_handle           varbinary(64)   Not Null\n        , statementExecutions   int             Not Null\n    );\n\n    Create Table #missingIndexes\n    (\n          databaseID            int             Not Null\n        , objectID              int             Not Null\n        , query_plan            xml             Not Null\n        , statementExecutions   int             Not Null\n    );\n    \n    Create Clustered Index CIX_temp_missingIndexes\n        On #missingIndexes(databaseID, objectID);\n       \n    Begin Try\n\n        /* Perform some data validation */\n        If @logResults = 0 And @displayResults = 0\n        Begin\n\n            /* Log the fact that there were open transactions */\n            Execute dbo.dba_logError_sp\n                  @errorType            = 'app'\n                , @app_errorProcedure   = 'dba_missingIndexStoredProc_sp'\n                , @app_errorMessage     = '@logResults = 0 and @displayResults = 0; no action taken, exiting stored proc.'\n                , @forceExit            = 1\n                , @returnError          = 1;  \n\n        End;\n\n        Begin Transaction;\n\n        /* Retrieve distinct plan handles to minimize dm_exec_query_plan lookups */\n        Insert Into @plan_handles\n        Select plan_handle, Sum(execution_count) As 'executions'\n        From sys.dm_exec_query_stats\n        Where last_execution_time > DateAdd(day, -@lastExecuted_inDays, @currentDateTime)\n        Group By plan_handle\n        Having Sum(execution_count) > @minExecutionCount;\n\n        With xmlNameSpaces (\n            Default 'http://schemas.microsoft.com/sqlserver/2004/07/showplan'\n        )\n\n        /* Retrieve our query plan's XML if there's a missing index */\n        Insert Into #missingIndexes\n        Select deqp.[dbid]\n            , deqp.objectid\n            , deqp.query_plan \n            , ph.statementExecutions\n        From @plan_handles As ph\n        Cross Apply sys.dm_exec_query_plan(ph.plan_handle) As deqp \n        Where deqp.query_plan.exist('//MissingIndex/@Database') = 1\n            And deqp.objectid Is Not Null;\n\n        /* Do we want to store the results of our process? */\n        If @logResults = 1\n        Begin\n            Insert Into dbo.dba_missingIndexStoredProc\n            Execute sp_msForEachDB 'Use ?; \n                                    Select ''?''\n                                        , mi.databaseID\n                                        , Object_Name(o.object_id)\n                                        , o.object_id\n                                        , mi.query_plan\n                                        , GetDate()\n                                        , mi.statementExecutions\n                                    From sys.objects As o \n                                    Join #missingIndexes As mi \n                                        On o.object_id = mi.objectID \n                                    Where databaseID = DB_ID();';\n\n        End\n        /* We're not logging it, so let's display it */\n        Else\n        Begin\n            Execute sp_msForEachDB 'Use ?; \n                                    Select ''?''\n                                        , mi.databaseID\n                                        , Object_Name(o.object_id)\n                                        , o.object_id\n                                        , mi.query_plan\n                                        , GetDate()\n                                        , mi.statementExecutions\n                                    From sys.objects As o \n                                    Join #missingIndexes As mi \n                                        On o.object_id = mi.objectID \n                                    Where databaseID = DB_ID();';\n        End;\n\n        /* See above; this part will only work if we've \n           logged our data. */\n        If @displayResults = 1 And @logResults = 1\n        Begin\n            Select *\n            From dbo.dba_missingIndexStoredProc\n            Where executionDate >= @currentDateTime;\n        End;\n\n        /* If you have an open transaction, commit it */\n        If @@TranCount > 0\n            Commit Transaction;\n\n    End Try\n    Begin Catch\n\n        /* Whoops, there was an error... rollback! */\n        If @@TranCount > 0\n            Rollback Transaction;\n\n        /* Return an error message and log it */\n        Execute dbo.dba_logError_sp;\n\n    End Catch;\n\n    /* Clean-Up! */\n    Drop Table #missingIndexes;\n\n    Set NoCount Off;\n    Return 0;\nEnd\nGo\n\nSet Quoted_Identifier Off;\nGo"
  },
  {
    "path": "indexes/index_definition.sql",
    "content": "/**********************************************************************************************************\n\n    NAME:           index_definition.sql\n\n    SYNOPSIS:       Displays the definition of indexes; useful to audit indexes across servers & environments\n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2012-10-15\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n\n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20150619   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\n-- Single database\n\nWITH indexCTE AS\n(\n    SELECT st.object_id                                                                         AS objectID\n        , st.name                                                                               AS tableName\n        , si.index_id                                                                           AS indexID\n        , si.name                                                                               AS indexName\n        , si.type_desc                                                                          AS indexType\n        , sc.column_id                                                                          AS columnID\n        , sc.name + CASE WHEN sic.is_descending_key = 1 THEN ' DESC' ELSE '' END                AS columnName\n        , sic.key_ordinal                                                                       AS ordinalPosition\n        , CASE WHEN sic.is_included_column = 0 AND key_ordinal > 0 THEN sc.name ELSE NULL END   AS indexKeys\n        , CASE WHEN sic.is_included_column = 1 THEN sc.name ELSE NULL END                       AS includedColumns\n        , sic.partition_ordinal                                                                 AS partitionOrdinal\n        , CASE WHEN sic.partition_ordinal > 0 THEN sc.name ELSE NULL END                        AS partitionColumns\n        , si.is_primary_key                                                                     AS isPrimaryKey\n        , si.is_unique                                                                          AS isUnique\n        , si.is_unique_constraint                                                               AS isUniqueConstraint\n        , si.has_filter                                                                         AS isFilteredIndex\n        , COALESCE(si.filter_definition, '')                                                    AS filterDefinition\n    FROM sys.tables                         AS st\n    INNER JOIN sys.indexes                  AS si \n        ON si.object_id =   st.object_id\n    INNER JOIN sys.index_columns            AS sic \n\t    ON sic.object_id=si.object_id\n        AND sic.index_id=si.index_id \n    INNER JOIN sys.columns                  AS sc \n\t    ON sc.object_id = sic.object_id \n\t    and sc.column_id = sic.column_id\n) \n\nSELECT DISTINCT \n      @@SERVERNAME                                      AS ServerName\n    , DB_NAME()                                         AS DatabaseName\n    , tableName\n    , indexName\n    , indexType\n    , STUFF((\n            SELECT ', ' + indexKeys\n                FROM indexCTE\n            WHERE objectID = cte.objectID\n                AND indexID = cte.indexID\n                AND indexKeys IS NOT NULL \n            ORDER BY ordinalPosition\n                FOR XML PATH(''), \n      TYPE).value('.','varchar(max)'),1,1,'')           AS indexKeys\n    , COALESCE(STUFF((\n            SELECT ', ' + includedColumns\n                FROM indexCTE\n            WHERE objectID = cte.objectID\n                AND indexID = cte.indexID\n                AND includedColumns IS NOT NULL \n            ORDER BY columnID\n                FOR XML PATH(''), \n      TYPE).value('.','varchar(max)'),1,1,''), '')      AS includedColumns\n    , COALESCE(STUFF((\n            SELECT ', ' + partitionColumns\n                FROM indexCTE\n            WHERE objectID = cte.objectID\n                AND indexID = cte.indexID\n                AND partitionColumns IS NOT NULL \n            ORDER BY partitionOrdinal\n                FOR XML PATH(''), \n      TYPE).value('.','varchar(max)'),1,1,''), '')      AS partitionKeys\n    , isPrimaryKey\n    , isUnique\n    , isUniqueConstraint\n    , isFilteredIndex\n    , FilterDefinition\nFROM indexCTE AS cte\nWHERE tableName = 'your_example'\nORDER BY tableName\n    , indexName;\n\n/*********************************************************************************************************/\n\n-- All databases\nIF OBJECT_ID('tempdb..#IndexAudit') IS NOT NULL\n    DROP TABLE #IndexAudit;\n\nCREATE TABLE #IndexAudit\n(\n      serverName                SYSNAME\n    , databaseName              SYSNAME\n    , tableName                 VARCHAR(128)\n    , indexName                 VARCHAR(128)\n    , indexType                 NVARCHAR(60)\n    , indexKeys                 VARCHAR(8000)\n    , includedColumns           VARCHAR(8000)\n    , partitionColumns          VARCHAR(8000)\n    , isPrimaryKey              BIT\n    , isUnique                  BIT\n    , isUniqueConstraint        BIT\n    , isFilteredIndex           BIT\n    , FilterDefinition          VARCHAR(8000)\n);\n\nEXECUTE sp_foreachdb 'USE ?;\nWITH indexCTE AS\n(\n    SELECT st.object_id                                                                         AS objectID\n        , st.name                                                                               AS tableName\n        , si.index_id                                                                           AS indexID\n        , si.type_desc                                                                          AS indexType\n        , si.name                                                                               AS indexName\n        , sc.column_id                                                                          AS columnID\n        , sc.name + CASE WHEN sic.is_descending_key = 1 THEN '' DESC'' ELSE '''' END            AS columnName\n        , sic.key_ordinal                                                                       AS ordinalPosition\n        , CASE WHEN sic.is_included_column = 0 AND key_ordinal > 0 THEN sc.name ELSE NULL END   AS indexKeys\n        , CASE WHEN sic.is_included_column = 1 THEN sc.name ELSE NULL END                       AS includedColumns\n        , sic.partition_ordinal                                                                 AS partitionOrdinal\n        , CASE WHEN sic.partition_ordinal > 0 THEN sc.name ELSE NULL END                        AS partitionColumns\n        , si.is_primary_key                                                                     AS isPrimaryKey\n        , si.is_unique                                                                          AS isUnique\n        , si.is_unique_constraint                                                               AS isUniqueConstraint\n        , si.has_filter                                                                         AS isFilteredIndex\n        , COALESCE(si.filter_definition, '''')                                                  AS filterDefinition\n    FROM sys.tables                         AS st\n    INNER JOIN sys.indexes                  AS si \n        ON si.object_id =   st.object_id\n    INNER JOIN sys.index_columns            AS sic \n\t    ON sic.object_id=si.object_id\n        AND sic.index_id=si.index_id \n    INNER JOIN sys.columns                  AS sc \n\t    ON sc.object_id = sic.object_id \n\t    and sc.column_id = sic.column_id\n) \n\nINSERT INTO #IndexAudit\nSELECT DISTINCT \n      @@SERVERNAME                                              AS ServerName\n    , DB_NAME()                                                 AS DatabaseName\n    , tableName\n    , indexName\n    , indexType\n    , STUFF((\n            SELECT '', '' + indexKeys\n                FROM indexCTE\n            WHERE objectID = cte.objectID\n                AND indexID = cte.indexID\n                AND indexKeys IS NOT NULL \n            ORDER BY ordinalPosition\n                FOR XML PATH(''''), \n      TYPE).value(''.'',''varchar(max)''),1,1,'''')             AS indexKeys\n    , COALESCE(STUFF((\n            SELECT '', '' + includedColumns\n                FROM indexCTE\n            WHERE objectID = cte.objectID\n                AND indexID = cte.indexID\n                AND includedColumns IS NOT NULL \n            ORDER BY columnID\n                FOR XML PATH(''''), \n      TYPE).value(''.'',''varchar(max)''),1,1,''''), '''')      AS includedColumns\n    , COALESCE(STUFF((\n            SELECT '', '' + partitionColumns\n                FROM indexCTE\n            WHERE objectID = cte.objectID\n                AND indexID = cte.indexID\n                AND partitionColumns IS NOT NULL \n            ORDER BY partitionOrdinal\n                FOR XML PATH(''''), \n      TYPE).value(''.'',''varchar(max)''),1,1,''''), '''')      AS partitionKeys\n    , isPrimaryKey\n    , isUnique\n    , isUniqueConstraint\n    , isFilteredIndex\n    , FilterDefinition\nFROM indexCTE AS cte\nORDER BY tableName\n    , indexName;\n';\n\n-- For multi-server testing, dump results to a temp table and compare tables\nSELECT *\nFROM #IndexAudit\nWHERE databaseName NOT IN ('tempdb', 'master', 'msdb', 'model')\nORDER BY serverName\n    , databaseName\n    , tableName\n    , indexName;"
  },
  {
    "path": "indexes/missing.sql",
    "content": "/**********************************************************************************************************\n\n    NAME:           missing.sql\n\n    SYNOPSIS:       Displays potential missing indexes for a given database. Adding the indexes via the\n                    provided CREATE scripts may improve server performance. \n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2014-04-08\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n    \n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20140408   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\nSELECT \n      t.name AS 'affected_table'\n    , 'CREATE NONCLUSTERED INDEX IX_' + t.name + '_missing_'\n        + CONVERT(CHAR(8), GETDATE(), 112) + '_'\n        + CAST(ROW_NUMBER() OVER (PARTITION BY t.name \n            ORDER BY CAST((ddmigs.user_seeks + ddmigs.user_scans) \n                * ddmigs.avg_user_impact AS BIGINT) DESC) AS VARCHAR(3))\n        + ' ON ' + ddmid.statement \n        + ' (' + ISNULL(ddmid.equality_columns,'') \n        + CASE WHEN ddmid.equality_columns IS NOT NULL \n            AND ddmid.inequality_columns IS NOT NULL THEN ',' \n                ELSE '' END \n        + ISNULL(ddmid.inequality_columns, '')\n        + ')' \n        + ISNULL(' INCLUDE (' + ddmid.included_columns + ');', ';'\n        ) AS sql_statement\n    , ddmigs.user_seeks\n    , ddmigs.user_scans\n    , CAST((ddmigs.user_seeks + ddmigs.user_scans) \n        * ddmigs.avg_user_impact AS BIGINT) AS 'est_impact'\n    , ddmigs.last_user_seek\nFROM sys.dm_db_missing_index_groups                                 AS ddmig\nINNER JOIN sys.dm_db_missing_index_group_stats                      AS ddmigs\n    ON ddmigs.group_handle = ddmig.index_group_handle\nINNER JOIN sys.dm_db_missing_index_details                          AS ddmid \n    ON ddmig.index_handle = ddmid.index_handle\nINNER JOIN sys.tables                                               AS t\n    ON ddmid.[object_id] = t.[object_id]\nWHERE ddmid.database_id  =  DB_ID()                                                             ----> by default, only examines the current database\n  AND CAST((ddmigs.user_seeks + ddmigs.user_scans) * ddmigs.avg_user_impact AS BIGINT)  >  100  ----> 100 is a starting point; update value as appropriate\nORDER BY CAST((ddmigs.user_seeks + ddmigs.user_scans) * ddmigs.avg_user_impact AS BIGINT) DESC;"
  },
  {
    "path": "indexes/unused.sql",
    "content": "/**********************************************************************************************************\n\n    NAME:           unused.sql\n\n    SYNOPSIS:       Displays potential unused indexes for the current database. Dropping these indexes \n                    may improve database performance. These statistics are reset each time the server \n                    is rebooted, so make sure to review the [sqlserver_start_time] value to ensure the \n                    statistics are captured for a meaningful time period.\n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2014-04-08\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n    \n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20140408   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\n\nSELECT sqlserver_start_time FROM sys.dm_os_sys_info;\n\nDECLARE @dbid INT\n    , @dbName VARCHAR(100);\n\nSELECT @dbid = DB_ID()\n    , @dbName = DB_NAME();\n\nWITH partitionCTE (object_id, index_id, row_count, partition_count) \nAS\n(\n    SELECT [object_id]\n        , index_id\n        , SUM([rows]) AS 'row_count'\n        , COUNT(partition_id) AS 'partition_count'\n    FROM sys.partitions\n    GROUP BY [object_id]\n        , index_id\n)\n\nSELECT OBJECT_NAME(i.[object_id]) AS objectName\n        , i.name\n        , CASE \n            WHEN i.is_unique = 1 \n                THEN 'UNIQUE ' \n            ELSE '' \n          END + i.type_desc AS 'indexType'\n        , ddius.user_seeks\n        , ddius.user_scans\n        , ddius.user_lookups\n        , ddius.user_updates\n        , cte.row_count\n        , CASE WHEN partition_count > 1 THEN 'yes' \n            ELSE 'no' END AS 'partitioned?'\n        , CASE \n            WHEN i.type = 2 AND i.is_unique = 0\n                THEN 'Drop Index ' + i.name \n                    + ' On ' + @dbName \n                    + '.dbo.' + OBJECT_NAME(ddius.[object_id]) + ';'\n            WHEN i.type = 2 AND i.is_unique = 1\n                THEN 'Alter Table ' + @dbName \n                    + '.dbo.' + OBJECT_NAME(ddius.[object_ID]) \n                    + ' Drop Constraint ' + i.name + ';'\n            ELSE '' \n          END AS 'SQL_DropStatement'\nFROM sys.indexes                                                        AS i\nINNER JOIN sys.dm_db_index_usage_stats                                  AS ddius\n    ON i.object_id = ddius.object_id\n        AND i.index_id = ddius.index_id\nINNER JOIN partitionCTE                                                 AS cte\n    ON i.object_id = cte.object_id\n        AND i.index_id = cte.index_id\nWHERE ddius.database_id = @dbid\n    AND i.type = 2                                                      ----> retrieve nonclustered indexes only\n    AND i.is_unique = 0                                                 ----> ignore unique indexes, we'll assume they're serving a necessary business use\n    AND (ddius.user_seeks + ddius.user_scans + ddius.user_lookups) = 0  ----> starting point, update this value as needed; 0 retrieves completely unused indexes\nORDER BY user_updates DESC;\n\n"
  },
  {
    "path": "misc/dba_viewPageData_sp.sql",
    "content": "If ObjectProperty(Object_ID('dbo.dba_viewPageData_sp'), N'IsProcedure') Is Null\nBegin\n    Execute ('Create Procedure dbo.dba_viewPageData_sp As Print ''Hello World!''')\n    RaisError('Procedure dba_viewPageData_sp created.', 10, 1);\nEnd;\nGo\n\nSet ANSI_Nulls On;\nSet Quoted_Identifier On;\nGo\n\nAlter Procedure dbo.dba_viewPageData_sp\n\n        /* Declare Parameters */\n          @databaseName varchar(128)\n        , @tableName    varchar(128)    = Null -- database.schema.tableName\n        , @indexName    varchar(128)    = Null\n        , @fileNumber   int             = Null\n        , @pageNumber   int             = Null\n        , @printOption  int             = 3    -- 0, 1, 2, or 3\n        , @pageType     char(4)         = 'Leaf' -- Leaf, Root, or IAM\n        \nAs\n/**********************************************************************************************************\n\n    NAME:           dba_viewPageData_sp\n\n    SYNOPSIS:       Retrieves page data for the specified table/page.\n\n    DEPENDENCIES:   The following dependencies are required to execute this script:\n                    - SQL Server 2005 or newer\n                    \n    NOTES:          Can pass either the table name or the pageID, but must pass one, or\n                    you'll end up with no results. \n                    If the table name is passed, it will return the first page.\n    \n                    @tableName must be '<databaseName>.<schemaName>.<tableName>' in order to\n                        function correctly.  When called within the same database, the database\n                        prefix may be omitted.  \n            \n                    @printOption can be one of following values:\n                        0 - print just the page header\n                        1 - page header plus per-row hex dumps and a dump of the page slot array\n                        2 - page header plus whole page hex dump\n                        3 - page header plus detailed per-row interpretation\n                        \n                    Page Options borrowed from: \n                    https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/10/625659.aspx\n            \n                    @pageType must be one of the following values:\n                        Leaf - returns the first page of the leaf level of your index or heap\n                        Root - returns the root page of your index\n                        IAM - returns the index allocation map chain for your index or heap\n            \n                    Conversions borrowed from:\n                    http://sqlskills.com/blogs/paul/post/Inside-The-Storage-Engine-\n                    sp_AllocationMetadata-putting-undocumented-system-catalog-views-to-work.aspx\n\n    AUTHOR:         Michelle Ufford, http://sqlfool.com\n    \n    CREATED:        2009-05-06\n    \n    VERSION:        1.0\n\n    LICENSE:        Apache License v2\n    \n    USAGE:          EXEC dbo.dba_viewPageData_sp\n                      @databaseName = 'AdventureWorks'\n                    , @tableName    = 'AdventureWorks.Sales.SalesOrderDetail'\n                    , @indexName    = 'IX_SalesOrderDetail_ProductID'\n                    --, @fileNumber   = 1\n                    --, @pageNumber   = 38208\n                    , @printOption  = 3\n                    , @pageType     = 'Root';\n\n    ----------------------------------------------------------------------------\n    DISCLAIMER: \n    This code and information are provided \"AS IS\" without warranty of any kind,\n    either expressed or implied, including but not limited to the implied \n    warranties or merchantability and/or fitness for a particular purpose.\n    ----------------------------------------------------------------------------\n\n ---------------------------------------------------------------------------------------------------------\n --  DATE       VERSION     AUTHOR                  DESCRIPTION                                        --\n ---------------------------------------------------------------------------------------------------------\n     20150619   1.0         Michelle Ufford         Open Sourced on GitHub\n**********************************************************************************************************/\n\nSet NoCount On;\nSet XACT_Abort On;\nSet Ansi_Padding On;\nSet Ansi_Warnings On;\nSet ArithAbort On;\nSet Concat_Null_Yields_Null On;\nSet Numeric_RoundAbort Off;\n\nBegin\n\n    Declare @fileID         int\n        , @pageID           int\n        , @sqlStatement     nvarchar(1200)\n        , @sqlParameters    nvarchar(255)\n        , @errorMessage     varchar(100);\n\n    Begin Try\n\n        If @fileNumber Is Null And @pageNumber Is Null And @tableName Is Null\n        Begin\n            Set @errorMessage = 'You must provide either a file/page number, or a table name!';\n            RaisError(@errorMessage, 16, 1);\n        End;\n            \n        If @pageType Not In ('Leaf', 'Root', 'IAM')\n        Begin\n            Set @errorMessage = 'You have entered an invalid page type; valid options are \"Leaf\", \"Root\", or \"IAM\"';\n            RaisError(@errorMessage, 16, 1);\n        End;\n\n        If @fileNumber Is Null Or @pageNumber Is Null\n        Begin\n        \n            Set @sqlStatement = \n            Case When @pageType = 'Leaf' Then\n                'Select Top 1 @p_fileID = Convert (varchar(6), Convert (int, \n                    SubString (au.first_page, 6, 1) +\n                    SubString (au.first_page, 5, 1)))\n                , @p_pageID = Convert (varchar(20), Convert (int, \n                     SubString (au.first_page, 4, 1) +\n                     SubString (au.first_page, 3, 1) +\n                     SubString (au.first_page, 2, 1) +\n                     SubString (au.first_page, 1, 1)))'\n            When @pageType = 'Root' Then\n                'Select Top 1 @p_fileID = Convert (varchar(6), Convert (int, \n                    SubString (au.root_page, 6, 1) +\n                    SubString (au.root_page, 5, 1)))\n                , @p_pageID = Convert (varchar(20), Convert (int, \n                     SubString (au.root_page, 4, 1) +\n                     SubString (au.root_page, 3, 1) +\n                     SubString (au.root_page, 2, 1) +\n                     SubString (au.root_page, 1, 1)))'\n            When @pageType = 'IAM' Then\n                'Select Top 1 @p_fileID = Convert (varchar(6), Convert (int, \n                    SubString (au.first_iam_page, 6, 1) +\n                    SubString (au.first_iam_page, 5, 1)))\n                , @p_pageID = Convert (varchar(20), Convert (int, \n                     SubString (au.first_iam_page, 4, 1) +\n                     SubString (au.first_iam_page, 3, 1) +\n                     SubString (au.first_iam_page, 2, 1) +\n                     SubString (au.first_iam_page, 1, 1)))'\n            End + \n            'From ' + QuoteName(ParseName(@databaseName, 1)) + '.sys.indexes AS i\n            Join ' + QuoteName(ParseName(@databaseName, 1)) + '.sys.partitions AS p\n                On i.[object_id] = p.[object_id]\n                And i.index_id = p.index_id\n            Join ' + QuoteName(ParseName(@databaseName, 1)) + '.sys.system_internals_allocation_units AS au\n                On p.hobt_id = au.container_id\n            Where p.[object_id] = Object_ID(@p_tableName)\n                And au.first_page > 0x000000000000 ' \n                + Case When @indexName Is Null \n                    Then ';' \n                    Else 'And i.name = @p_indexName;' End;\n\n            Set @sqlParameters = '@p_tableName varchar(128)\n                                , @p_indexName varchar(128)\n                                , @p_fileID int OUTPUT\n                                , @p_pageID int OUTPUT';\n            \n            Execute sp_executeSQL @sqlStatement\n                        , @sqlParameters\n                        , @p_tableName = @tableName\n                        , @p_indexName = @indexName\n                        , @p_fileID = @fileID OUTPUT\n                        , @p_pageID = @pageID OUTPUT;\n\n            End\n            Else\n            Begin\n                Select @fileID = @fileNumber\n                    , @pageID = @pageNumber;\n            End;\n\n        DBCC TraceOn (3604);\n        DBCC Page (@databaseName, @fileID, @pageID, @printOption);\n        DBCC TraceOff (3604);\n\n    End Try\n    Begin Catch\n    \n        Print @errorMessage;\n    \n    End Catch;\n\n    Set NoCount Off;\n    Return 0;\nEnd\nGo\n\nSet Quoted_Identifier Off;\nGo"
  }
]