{"id":875,"date":"2010-04-29T00:00:00","date_gmt":"2010-04-29T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/exploring-sql-server-table-metadata-with-ssms-and-tsql\/"},"modified":"2021-09-29T16:21:59","modified_gmt":"2021-09-29T16:21:59","slug":"exploring-sql-server-table-metadata-with-ssms-and-tsql","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/t-sql-programming-sql-server\/exploring-sql-server-table-metadata-with-ssms-and-tsql\/","title":{"rendered":"Exploring SQL Server table metadata with SSMS and TSQL"},"content":{"rendered":"<div id=\"pretty\">\n<p class=\"start\">When you are using Management Studio, it would be nice to be able to select the name of an object, particularly a table, and to instantly see, at a keystroke, the build script in the results pane, complete with the documentation and, in the case of a table, the referential constraints. It would also be nice to get a list of all the places in the database where the object&#8217;s name appears. <\/p>\n<p>A dream? I&#8217;ll show you in this article how to make this happen, and lots more.<\/p>\n<p>First, a brief demo of what I mean.&#160; I have a blank query window. I wonder what tables I have in my database and what they&#8217;re for. &#160;I hit my query shortcut <b>Control 6. <\/b>This appears in the results pane.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1021-IHitControl6.jpg\" width=\"606\" height=\"288\" alt=\"1021-IHitControl6.jpg\" \/><\/p>\n<p>We have&#160; a list of tables for the database we are investigating (OK! It is AdventureWorks, i&#8217;ll admit). Hmm. We&#8217;ll pop them into the query pane in order to explore them. So, what is this table &#8216;ProductReview?. We hit Control 3 and instantly out it pops, the build script.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1021-IHitControl3.jpg\" width=\"611\" height=\"490\" alt=\"1021-IHitControl3.jpg\" \/><\/p>\n<p>I have turned this query window into a powerful table-inspector, but I could have done it&#160; for procedures, functions or triggers.&#160; I can do other things, of course. How about telling me where the string &#8216;productReview&#8217; occurs? Select it and hit cntl 4<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1021-IHitControl4.jpg\" width=\"613\" height=\"492\" alt=\"1021-IHitControl4.jpg\" \/><\/p>\n<p>How do I do this? There exists in SSMS a very useful facility for executing particular stored procedures or simple SQL expressions of your choice. There are a number of special keyboard shortcuts that are reserved for the user. These are called the Query Shortcuts and are accessed with ALT F1 Ctl F1, and Ctl 1 &#8230;Ctl 0.&#160;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1021-options.jpg\" width=\"600\" height=\"349\" alt=\"1021-options.jpg\" \/><\/p>\n<p>&#160;Normally, you use these to invoke the system stored procedures sp_Help, sp_HelpText and sp_Who. The other nine slots are left enticingly blank for your own routines or queries. You can get in there and add your own, but these will only work in Query Windows that you open subsequently!&#160; <\/p>\n<p>Of course, for information such as that build script you&#8217;ll probably need to set the results window to text, and increase the no. of characters displayed in each column to a sensible level such as 8000 chars<\/p>\n<p>If you highlight text in the code pane of the query window in SSMS or QA, and then invoke code that is slotted into one of these keyboard shortcuts, whatever you highlight is appended &#8216;as-is&#8217; to what is executed. This means that if you want to pass a string to a procedure it will need to be a valid delimited string, escaped if necessary. If it is a valid object name, it is coerced successfully into a string. This means that you can pass the names of an object, but a qualified object name would have to be delimited properly. <\/p>\n<p>Most of the code that I have in Query Shortcuts in my copy of SSMS is for getting lists of tables, procedures, parameters and so on. I haven&#8217;t hit a limit for the length of the expression, but it has to be all in one line. (see the screen-scrape of the Options tab above)<\/p>\n<p>There are a number of queries that can go in one line that provide useful information before &#160;you become forced to use a stored procedure. The sort of queries that work are the ones that don&#8217;t require parameters.&#160; <\/p>\n<p>There is a lot that can be done here like:&#8230;.<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">--list all the tables&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \nSELECT name AS [Tables] FROM sys.objects WHERE OBJECTPROPERTY(object_id, 'isUserTable')&lt;&gt;0\n--list all the Scalar functions\nSELECT name AS [Scalar functions] FROM sys.objects WHERE OBJECTPROPERTY(object_id, 'IsScalarFunction')&lt;&gt;0\n--list all the Table Functions\nSELECT name AS [Table Functions] FROM sys.objects WHERE OBJECTPROPERTY(object_id, 'IsTableFunction')&lt;&gt;0\n--list all the Procedures\nSELECT name AS [Procedures] FROM sys.objects WHERE OBJECTPROPERTY(object_id, 'IsProcedure')&lt;&gt;0\n--list all the Triggers\nSELECT name AS [Triggers] FROM sys.objects WHERE OBJECTPROPERTY(object_id, 'IsTrigger')&lt;&gt;0\n<\/pre>\n<p>&#8230;And a host of other queries you can work out from <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms176105(v=SQL.100).aspx\">here<\/a>. Of course, you can elaborate them. Here is some code that shows you all your functions along with their parameters, and any extended property: (but I won&#8217;t show it to you all in one long line as it will have to be for use)<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT\n&#160; so.name+REPLACE(\n&#160;&#160;&#160;&#160; '('+COALESCE((SELECT name+', ' FROM sys.parameters sp\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE sp.object_ID=so.object_ID AND parameter_ID&gt;0\n&#160;&#160;&#160;&#160;&#160; ORDER BY&#160; parameter_ID\n&#160;&#160;&#160;&#160;&#160; FOR XML PATH('')), '')+')',\n&#160; ', )', ')')+COALESCE('&#160; \/*'+CONVERT(VARCHAR(300), value)+'*\/','') [Scalar functions]\nFROM\n&#160; sys.objects so\nLEFT OUTER JOIN sys.extended_properties ep \/*get any extended properties*\/\n&#160; ON ep.name LIKE 'MS_Description' AND major_ID=so.object_ID\nWHERE\n&#160; OBJECTPROPERTY(object_id, 'IsScalarFunction')&lt;&gt;0\n<\/pre>\n<p>With a moment&#8217;s thought, you&#8217;ll see a number of possibilities. In the past two articles in this series, I&#8217;ve given a few ideas: There are plenty more. What, for example, about listing out all tables along with a list of columns that can then be used for Select and update statements? Easy. Then you can just keep the list handy somewhere when doing some development work (I use AceText but you can use Notepad if you have nothing better). Here is the routine for the Table-lister I used earlier.<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT\n&#160; so.name+REPLACE(\n&#160;&#160;&#160;&#160; ' ('+COALESCE((SELECT name+', ' FROM sys.columns sp\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE sp.object_ID=so.object_ID AND column_ID&gt;0\n&#160;&#160;&#160;&#160;&#160; ORDER BY&#160; column_ID\n&#160;&#160;&#160;&#160;&#160; FOR XML PATH('')), '')+')',\n&#160; ', )', ')')+COALESCE('&#160; \/*'+CONVERT(VARCHAR(300), value)+'*\/','') [Tables]\nFROM\n&#160; sys.objects so\nLEFT OUTER JOIN sys.extended_properties ep&#160;\/* get any extended properties *\/\n&#160; ON ep.name LIKE 'MS_Description' AND major_ID=so.object_ID and minor_ID=0\nWHERE\n&#160; OBJECTPROPERTY(object_id, 'IsUserTable')&lt;&gt;0\n<\/pre>\n<p>With a moment&#8217;s thought, you&#8217;ll notice that you can elaborate this to give you the complete select statement for tables, including all the comments, for all your database tables.&#160; This is suddenly powerful magic, particularly as you can take out the new-lines and it all executes fine from a Query Shortcut key.&#160; <\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT '\/* '+qualifiedName+' *\/'+CHAR(13)+CHAR(10)+REPLACE(\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; REPLACE( \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; STUFF(SelectScript, \/*delete final comma line-terminator*\/\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; LEN(SelectScript)-CHARINDEX('|,|',\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; REVERSE(SelectScript)+'|')-1,3\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ,'')\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;,'\\n',CHAR(13)+CHAR(10))\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ,'|,|',',') \/*put in new-lines and convert token to comma*\/&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \nFROM (SELECT \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; so.name AS Name, \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; OBJECT_SCHEMA_NAME(so.object_ID)+'.'+so.name AS qualifiedName,\n&#160;&#160;&#160;&#160;&#160;&#160; &#160; 'SELECT '+REPLACE(COALESCE(\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160; (\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160; SELECT '\\n&#160;&#160;&#160;&#160;&#160; '+QUOTENAME(sp.name)+'|,|'+COALESCE(' \/*'\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160; +CONVERT(VARCHAR(MAX),value)+'*\/','')\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160; FROM sys.columns sp\n&#160;&#160;&#160;&#160;&#160;&#160; &#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; LEFT OUTER JOIN sys.extended_properties ep\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ON sp.object_id = ep.major_ID&#160; \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;AND sp.column_ID = minor_ID AND class=1\n&#160;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160; WHERE sp.object_ID=so.object_ID\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; AND column_ID&gt;0\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160; ORDER BY column_ID\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160; FOR XML PATH('')\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;),'1')\n&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160; ,',||', '')\n&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160; +'\\nFROM&#160; '+QUOTENAME(OBJECT_SCHEMA_NAME(so.object_ID))+'.'\n&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160; +QUOTENAME(so.name)+COALESCE('&#160; \/*'\n&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160; +CONVERT(VARCHAR(300), value)+'*\/', '') [SelectScript]\n&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \n&#160;&#160;&#160;&#160;&#160;&#160; FROM\n&#160;&#160;&#160;&#160;&#160;&#160; &#160; sys.objects so\n&#160;&#160;&#160;&#160;&#160;&#160; &#160; LEFT OUTER JOIN sys.extended_properties ep\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/* get any extended properties *\/\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ON ep.name LIKE 'MS_Description'\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160; AND major_ID=so.object_ID\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160; AND minor_ID=0\n&#160;&#160;&#160;&#160;&#160;&#160; WHERE\n&#160;&#160;&#160;&#160;&#160;&#160; &#160; OBJECTPROPERTY(object_id, 'IsUserTable')&lt;&gt;0)f\nORDER BY name\n<\/pre>\n<p>This routine will create a select statement for every table in your database, including both table and column comments in extended properties. This will end up looking like this (Just one table in my sample)<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\/* Person.Address *\/\nSELECT \n&#160;&#160;&#160;&#160;&#160; [AddressID], \/*Primary key for Address records.*\/\n&#160;&#160;&#160;&#160;&#160; [AddressLine1], \/*First street address line.*\/\n&#160;&#160;&#160;&#160;&#160; [AddressLine2], \/*Second street address line.*\/\n&#160;&#160;&#160;&#160;&#160; [City], \/*Name of the city.*\/\n&#160;&#160;&#160;&#160;&#160; [StateProvinceID], \/*Unique identification number for the state or province. Foreign key to StateProvince table.*\/\n&#160;&#160;&#160;&#160;&#160; [PostalCode], \/*Postal code for the street address.*\/\n&#160;&#160;&#160;&#160;&#160; [rowguid], \/*ROWGUIDCOL number uniquely identifying the record. Used to support a merge replication sample.*\/\n&#160;&#160;&#160;&#160;&#160; [ModifiedDate] \/*Date and time the record was last updated.*\/\nFROM&#160; [Person].[Address]&#160; \/*Street address information for customers, employees, and vendors.*\/\n<\/pre>\n<p>You may wonder why I put the name of the table in comments at the start. This is so that it is easier to locate the table build script if your results pane is set to &#8216;grid&#8217; view.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1021-tableScripts.jpg\" alt=\"1021-tableScripts.jpg\" \/><\/p>\n<p>The script for Table-Valued Functions is even more complex, but this and the script for executing procedures can be useful if you take care to document your code using extended properties. (I use SQL Doc to make this easier to do). Your code starts looking a lot more readable and understandable.<\/p>\n<p>Every grey-muzzled database programmer will have a &#8216;thumb-drive&#8217; of favourite utility queries and routines to ease the development process. If you are clever with these, the requirement to continually poke and click all over SSMS to get anything done soon diminishes to a tolerable level and so your subsequent development work can get pretty much faster. <\/p>\n<p>You&#8217;ll notice a catch when you want to get to the next level of complexity. We want to highlight the name of a routine or table and hit a keyboard shortcut to get a build script and see what is really going on. &#160;We can&#8217;t use a query since the parameter ends up being appended. This is killer.&#160; We have to use a stored procedure<\/p>\n<p>Here we hit a particular problem, in that these keyboard query shortcuts are designed purely for use by system stored procedures, and they don&#8217;t easily lend themselves to use with normal stored procedures unless you propagate them to every database you are working on. &#160;As a general practice, I put my kit of development tools in Model in a dev schema so it automatically gets propagated to all my development databases as I create them. However, this is useless for a keyboard-shortcut tool and it can end up being accidentally included in a deployment. You&#8217;d have thought that a safer alternative would be to create a special &#8216;Dev&#8217; database for all your&#160; metadata-pummelling tools, but this would mean that your tools could only be evoked for that database! The only alternative to placing your dev routines in each database is to put them in the <b>MASTER<\/b> database. We are faced with needing to make a special plea to the DBA to be allowed to do this, add the sp_ prefix, and register the stored procedure as a system stored procedure, but you would end up having to redo it on every service pack and upgrade. Putting routines into the MASTER database isn&#8217;t generally a good idea, but I&#8217;m afraid that this particular extension of SSMS requires it if you wish to have more than the standard development stored procedures like <b>sp_help<\/b> and <b>sp_helptext.<\/b><\/p>\n<p>The magic of searching for where a string occurs in a database was done with the procedure I gave you at the end of the first article in this series. You&#8217;ll find it <a href=\"http:\/\/www.simple-talk.com\/sql\/t-sql-programming\/finding-stuff-in-sql-server-database-ddl\/\">here,<\/a> but you&#8217;ll have to change its name by giving an &#8216;sp_&#8217; prefix and put it in the master database, makking sure you register it too.<\/p>\n<p><b>Why bother to look at table build scripts?<\/b><\/p>\n<p>If you haven&#8217;t got SQL Prompt, table build scripts can be gotten from SSMS just by opening up the browser, clicking on the database, clicking on &#8216;tables&#8217;, and then right-clicking on the table you need information for. &#160;Then you need to select &#8216;script tables as&#8217; and finally choose a suitable target. &#160;When you finally get the table-build script, you&#8217;ll see that it isn&#8217;t designed for humans to see. The comments (<b>MS_Description<\/b>) for each column aren&#8217;t shown with the table, and the description of the table is lost half-way down the page. It isn&#8217;t usually clear which columns are foreign keys and what they are referring to. (they don&#8217;t use the clearer &#8216;<b>REFERENCES<\/b>&#8216; syntax for single-column foreign key constraints) It isn&#8217;t programmer-friendly. You&#8217;ll soon detect that doing things this way is fine for the database of your CD collection but not much else. For serious exploration of metadata, you need something much better. Ideally, of course, you&#8217;ll have everything to hand using SQL Doc, or some other third-party documenter, but the method I&#8217;m describing isn&#8217;t bad, and can be honed to your exact requirements..<\/p>\n<p><b>&#160;Under the hood.<\/b><\/p>\n<p>&#160;With stored procedures, views, triggers and functions, SQL Server stores the source. This is easy to fetch out. <\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">--find the actual code for a particular stored procedure, view, function etc. \nSelect object_Name(object_ID),definition from sys.SQL_Modules\nwhere object_Name(object_ID)='vEmployeeDepartment'\n&#160;\n--find the actual code for a particular stored procedure, view, function etc. \nSelect name, object_definition(object_ID)\nfrom sys.objects\nwhere object_ID=object_ID('HumanResources.vEmployeeDepartment')\n<\/pre>\n<p>If fetching table scripts were that easy, you wouldn&#8217;t need the rather scary script at the end of this article. However, tables aren&#8217;t held in script form in SQL Server because it would be difficult to synchronise the script with any changes you made with its child objects such as columns or constraints. SSMS uses SMO to reconstitute the build script. It is an elaborate process. Unike MySQL, there is no SQL command to produce a build script. Either we have to use SMO, or hand-craft a stored procedure to do it. <\/p>\n<p>There is a good reason why table-build scripts do not proliferate in SQL Server Blogs. They are hard to get right, and they&#8217;re a moving target with every revision of SQL Server. Here is my take on the problem, which aims to provide the script for any object. Remember, please, before you use this, that these are intended to allow you to get information about your objects such as tables, functions, procedures and so on. The table section, in particular will not give you a complete build script as I don&#8217;t bother with indexes. Oh no, this is for looking at.<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">USE MASTER\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\n&#160;\nGO\nIF EXISTS (SELECT 1 FROM sys.objects WHERE name LIKE 'sp_ScriptFor')\n&#160;&#160;&#160;&#160;&#160;&#160; DROP PROCEDURE sp_ScriptFor\ngo\nCREATE PROCEDURE [dbo].[sp_ScriptFor]\n@Identifier NVARCHAR(776)\n\/**\n\tsummary:&#160;&#160; &gt;\n\t&#160;This procedure returns an object build script as a single-row, single column\n\t&#160;result.\n\t&#160;Unlike the built-in OBJECT_DEFINITION, it also does tables.\n\t&#160;It copies the SMO style where possible but it uses the more intuitive\n\t&#160;eay of representing referential constraints and includes the documentation\n\t&#160;as comments that was, for unknown reasons, left out by Microsoft.\n\t&#160;You call it with the name of the table, either as a string, a valid table name,\n\t&#160;or as a schema-qualified table name in a string.\n\tRevisions: \n\t&#160;- Author: Phil Factor\n\t&#160;&#160; Version: 1.1\n\t&#160;&#160; Modification: dealt properly with heaps\n\t&#160;&#160; date: 20 Apr 2010\n\t&#160;- version: 1.2 \n\t&#160;&#160; modification: Removed several bugs and got column-level constraints working\n\t&#160;&#160; date: 1 Dec 2012\n\t&#160;- Version: 1.3 \n\t&#160;&#160; Modification: Added extended properties build\n\t&#160;&#160; date: 3 Dec 2012\n\texample:\n\t&#160;&#160;&#160;&#160; - code: sp_ScriptFor 'production.product'\n\t&#160;&#160;&#160;&#160; - code: sp_ScriptFor 'HumanResources.vEmployee'\n\t&#160;&#160;&#160;&#160; - code: sp_Scriptfor 'person.person'\n\t&#160;&#160;&#160;&#160; - code: execute AdventureWorks..sp_ScriptFor TransactionHistory\n\t&#160;&#160;&#160;&#160; - code: sp_ScriptFor 'HumanResources.uspUpdateEmployeeHireInfo'\n\treturns:&#160;&#160; &gt;\n\t&#160;single row, single column result Build_Script.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \n&#160;\n**\/\n&#160;\nAS\nDECLARE @Script VARCHAR(MAX)\nDECLARE @dbname SYSNAME\nDECLARE @PrimaryKeyBuild VARCHAR(MAX)\nIF CHARINDEX ('.',@identifier)=0 --Add schema if none given\n&#160;&#160;&#160;&#160;&#160;&#160; SELECT top 1 @Identifier=QUOTENAME(Object_Schema_name(s.object_id))\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; +'.'+QUOTENAME(s.name)\n&#160;&#160;&#160;&#160;&#160;&#160; FROM sys.objects s WHERE s.name LIKE @identifier\n&#160;\nSELECT @dbname = PARSENAME(@identifier,3)\n&#160;&#160;&#160;&#160;&#160;&#160; IF @dbname IS NULL\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; SELECT @dbname = DB_NAME()\n&#160;&#160;&#160;&#160;&#160;&#160; ELSE IF @dbname &lt;&gt; DB_NAME()\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; BEGIN\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; RAISERROR(15250,-1,-1)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; RETURN(1)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; END\n&#160;\nSELECT @Script=object_definition(OBJECT_ID(@Identifier))\nIF @script IS NULL\n&#160;&#160;&#160;&#160;&#160;&#160; IF (SELECT TYPE FROM sys.objects\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE object_id=OBJECT_ID(@Identifier))\n&#160;&#160;&#160;&#160;&#160; IN ('U','S')--if it is a table\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; BEGIN\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; SELECT @Script='\/*'+CONVERT(VARCHAR(2000),value)+'*\/\n'&#160;&#160;&#160;&#160;&#160;&#160; FROM&#160; sys.extended_properties ep\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE ep.major_ID = OBJECT_ID(@identifier)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; AND&#160; minor_ID=0 AND class=1\n&#160;\nSELECT @Script=COALESCE(@Script,'')+'CREATE TABLE '+@Identifier+'(\n&#160;&#160; ' +\n(SELECT QUOTENAME(c.name)+ ' '+&#160;&#160; coalesce(UDTs.UDTName,t.name)+' '\n&#160;&#160;&#160;&#160;&#160;&#160; + CASE WHEN is_computed=1 THEN ' AS '+ --do DDL for a computed column\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; (SELECT definition FROM sys.computed_columns cc\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE cc.object_id=c.object_id AND cc.column_ID=c.column_ID)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CASE WHEN\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; (SELECT is_persisted \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; FROM sys.computed_columns cc\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE cc.object_id=c.object_id\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; AND cc.column_ID=c.column_ID)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; =1 THEN 'PERSISTED' ELSE '' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; --we may have to put in the length&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHEN t.name IN ('char', 'varchar','nchar','nvarchar') THEN '('+\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; CASE WHEN c.max_length=-1 THEN 'MAX'\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ELSE CONVERT(VARCHAR(4),\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; CASE WHEN t.name IN ('nchar','nvarchar')\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; THEN&#160; c.max_length\/2 ELSE c.max_length END )\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; END +')'\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHEN t.name IN ('decimal','numeric')\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; THEN '('+ CONVERT(VARCHAR(4),c.precision)+','\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CONVERT(VARCHAR(4),c.Scale)+')'\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ELSE '' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CASE WHEN is_identity=1&#160; THEN 'IDENTITY ('\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CONVERT(VARCHAR(8),IDENT_SEED(Object_Schema_Name(c.object_id)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; +'.'+OBJECT_NAME(c.object_id)))+','\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CONVERT(VARCHAR(8),IDENT_INCR(Object_Schema_Name(c.object_id)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; +'.'+OBJECT_NAME(c.object_id)))+')' ELSE '' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CASE WHEN c.is_rowguidcol=1 THEN ' ROWGUIDCOL' ELSE '' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CASE WHEN XML_collection_ID&lt;&gt;0 THEN --deal with object schema names\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; '('+ CASE WHEN is_XML_Document=1\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; THEN 'DOCUMENT ' ELSE 'CONTENT ' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + COALESCE(\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; (SELECT QUOTENAME(ss.name)+'.' +QUOTENAME(sc.name)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; FROM sys.xml_schema_collections sc\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; INNER JOIN&#160; Sys.Schemas ss\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ON sc.schema_ID=ss.schema_ID\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE sc.xml_collection_ID=c.XML_collection_ID)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ,'NULL')\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; +')' ELSE '' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CASE WHEN&#160; is_identity=1\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; THEN CASE WHEN OBJECTPROPERTY(object_id, 'IsUserTable') = 1\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; AND COLUMNPROPERTY(object_id, c.name, 'IsIDNotForRepl') = 0\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; AND OBJECTPROPERTY(object_id, 'IsMSShipped') = 0\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; THEN '' ELSE ' NOT FOR REPLICATION ' END ELSE '' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CASE WHEN c.is_nullable=0 THEN ' NOT NULL' ELSE ' NULL' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CASE WHEN c.default_object_id &lt;&gt;0\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; THEN ' DEFAULT '+object_Definition(c.default_object_id) ELSE '' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CASE WHEN c.collation_name IS NULL THEN ''\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHEN&#160; c.collation_name&lt;&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; (SELECT collation_name FROM sys.databases\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE name=DB_NAME()) COLLATE Latin1_General_CI_AS\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; THEN COALESCE(' COLLATE '+c.collation_name,'') ELSE '' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; +coalesce(TheCheck,'')+&#160; coalesce(reference,'') +'|,|'&#160; \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CASE WHEN ep.value IS NOT NULL\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; THEN ' \/*'+CAST(value AS VARCHAR(100))+ '*\/' ELSE '' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CHAR(10)+'&#160;&#160; '\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; FROM sys.columns c INNER JOIN sys.types t\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ON c.user_Type_ID=t.user_Type_ID\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; LEFT OUTER JOIN sys.extended_properties ep --join to the comments\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ON c.object_id = ep.major_ID \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; AND c.column_ID = minor_ID AND class=1 \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160; left Outer join \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160; (Select column_ID,quotename(sys.schemas.name)+'.'+QuoteName(sys.types.name) as UDTname \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; from sys.columns inner join sys.types\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; on sys.types.user_type_id = sys.columns.user_type_id\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; inner join sys.schemas\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; on sys.schemas.schema_id=sys.types.schema_id\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; where object_ID=object_ID(@identifier) \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; and sys.columns.user_type_id &lt;&gt; sys.columns.system_type_id\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ) UDTs\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; on UDTs.column_ID=c.column_ID \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; inner join (SELECT cr.column_ID,(select case when is_system_named=0 then ' CONSTRAINT '+name else '' end+' CHECK '+definition \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160; FROM sys.check_constraints ccr\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; where cr.column_ID = ccr.parent_column_id\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; and ccr.parent_object_ID = cr.Object_ID\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160; FOR XML PATH(''), TYPE).value('.', 'varchar(max)') Thecheck\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; FROM sys.columns cr \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; where cr.Object_ID= OBJECT_ID(@identifier)) TheChecks\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; on theChecks.column_ID=c.column_ID\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; LEFT OUTER JOIN\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; (SELECT ' REFERENCES '\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; +COALESCE(SCHEMA_NAME(foreignRef.schema_ID)+'.','')\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; +OBJECT_NAME(fkc.referenced_object_id)+'('+c.name+') '--+\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CASE WHEN delete_referential_action_desc &lt;&gt; 'NO_ACTION'\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; THEN 'ON DELETE '\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + REPLACE(delete_referential_action_desc,'_',' ')\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; COLLATE database_default\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ELSE '' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CASE WHEN update_referential_action_desc &lt;&gt; 'NO_ACTION'\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; THEN 'ON UPDATE '\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + REPLACE(update_referential_action_desc,'_',' ')\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; COLLATE database_default\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ELSE '' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; AS reference, parent_column_id\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; FROM sys.foreign_key_columns fkc \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160;INNER JOIN sys.foreign_keys fk ON constraint_object_id=fk.object_ID\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; INNER JOIN sys.objects ForeignRef ON fkc.referenced_object_id=ForeignRef.Object_ID\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; INNER JOIN sys.columns c\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ON c.object_ID = fkc.referenced_object_id\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; AND c.column_ID = referenced_column_id\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE fk.parent_object_ID = OBJECT_ID(@identifier)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; AND constraint_object_ID NOT IN --include only single-column keys\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; (SELECT 1 FROM sys.foreign_key_columns multicolumn\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE multicolumn.parent_object_id =fk.parent_object_ID\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; GROUP BY constraint_object_id\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; HAVING COUNT(*)&gt;1)) column_references\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ON&#160; column_references.parent_column_ID=c.column_ID\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE object_id = OBJECT_ID(@identifier)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; ORDER BY c.column_ID\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; FOR XML PATH(''), TYPE).value('.', 'varchar(max)')--join up all the rows!\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; SELECT @Script=LEFT(@Script,LEN(@Script)-1)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; --take out the trailing line feed\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; SELECT TOP 1 @PrimaryKeyBuild=&#160; '\nCONSTRAINT ['+i.name+'] PRIMARY KEY '\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; +CASE WHEN type_desc='CLUSTERED' THEN 'CLUSTERED' ELSE '' END+'\n&#160;&#160; (\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; '&#160;&#160; + COALESCE(SUBSTRING((SELECT ','+COL_NAME(ic.object_id,ic.column_id)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; FROM&#160; sys.index_columns AS ic\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE ic.index_ID=i.index_ID AND ic.object_id=i.object_id\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ORDER BY key_ordinal\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; FOR XML PATH(''), TYPE).value('.', 'varchar(max)'),2,2000),'?')+'\n&#160;&#160; )WITH (PAD_INDEX&#160; = '\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; +CASE WHEN is_Padded&lt;&gt;0 THEN 'ON' ELSE 'OFF' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; +',&#160; IGNORE_DUP_KEY = '\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; +CASE WHEN ignore_dup_key&lt;&gt;0 THEN 'ON' ELSE 'OFF' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; +', ALLOW_ROW_LOCKS&#160; = '\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; +CASE WHEN allow_row_locks&lt;&gt;0 THEN 'ON' ELSE 'OFF' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; +', ALLOW_PAGE_LOCKS&#160; = '\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; +CASE WHEN allow_page_locks&lt;&gt;0 THEN 'ON' ELSE 'OFF' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; +') ON [PRIMARY]'+\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + CASE WHEN ep.value IS NOT NULL THEN '\n&#160; \/*'+CAST(value AS VARCHAR(100))+'*\/' ELSE '' END\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; FROM sys.indexes i\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; LEFT OUTER JOIN sys.extended_properties ep\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ON i.object_id = ep.major_ID&#160; AND i.index_ID = minor_ID AND class=7\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE OBJECT_NAME(object_id)=PARSENAME(@identifier,1) \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; AND is_primary_key =1\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; --and add the primary key build script and the ON PRIMARY, deleting the\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; --&#160; last comma-line-terminator if necessary. conver the |,| to commas\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; --&#160;&#160;&#160; \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; IF @PrimaryKeyBuild IS NULL\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; SELECT @Script=STUFF(@Script,--delete final comma line-terminator\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; LEN(@Script)-CHARINDEX('|,|',\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; REVERSE(@Script)+'|')-1,3\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ,'')\n\nDeclare @ExtendedPropertiesBuild Varchar(MAX)\nDeclare @ExtendedPropertyExecute Varchar(8000)\n\nSelect @ExtendedPropertyExecute='\nEXEC sys.sp_addextendedproperty N''MS_Description'', N''&lt;value&gt;'',\n&#160;&#160;&#160;&#160;&#160; N''SCHEMA'', N'''+object_Schema_Name(OBJECT_ID(@Identifier))+''', N''TABLE'', N'''+object_Name(OBJECT_ID(@Identifier))+'''' \n\nSelect @ExtendedPropertiesBuild=\n(Select Replace(@ExtendedPropertyExecute,'&lt;value&gt;',Replace(convert(varchar(max),value),'''',''''''))\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; +Coalesce(', '''+Level2Type+''', '''+Level2Name+'''','')\nfrom (&#160;&#160;&#160;&#160;&#160; \n&#160;&#160;&#160;&#160;&#160; select value, null as level2type ,null as level2Name\n&#160;&#160;&#160;&#160;&#160; &#160; from sys.extended_properties ep\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;WHERE ep.major_ID = OBJECT_ID(@Identifier)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;AND&#160; minor_ID=0 AND class=1\n&#160;&#160;&#160;&#160;&#160; union all \n&#160;&#160;&#160;&#160;&#160; &#160;\n&#160;&#160;&#160;&#160;&#160; select Value,'COLUMN',sys.columns.name\n&#160;&#160;&#160;&#160;&#160; &#160; from sys.extended_properties ep\n&#160;&#160;&#160;&#160;&#160; &#160; inner join sys.columns\n&#160;&#160;&#160;&#160;&#160; &#160; on sys.columns.column_ID=minor_ID\n&#160;&#160;&#160;&#160;&#160; &#160; and sys.columns.object_ID=major_ID\n&#160;&#160;&#160;&#160;&#160; &#160; WHERE ep.major_ID = OBJECT_ID(@Identifier)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;AND&#160; class=1 AND&#160; minor_ID&gt;0\n&#160;&#160;&#160;&#160;&#160; union all\n&#160;&#160;&#160;&#160;&#160; Select Value,'CONSTRAINT',object_name(ep.major_ID) \n&#160;&#160;&#160;&#160;&#160; from sys.extended_properties ep\n&#160;&#160;&#160;&#160;&#160; inner join sys.objects on object_ID=major_ID\n&#160;&#160;&#160;&#160;&#160; where parent_Object_ID=OBJECT_ID(@Identifier)\n&#160;&#160;&#160;&#160;&#160; and minor_ID=0\n&#160;&#160;&#160;&#160;&#160; union all\n&#160;&#160;&#160;&#160;&#160; Select Value,'INDEX', sys.indexes.name \n&#160;&#160;&#160;&#160;&#160; from sys.extended_properties ep\n&#160;&#160;&#160;&#160;&#160; inner join sys.indexes on object_ID=major_ID and index_ID=minor_ID\n&#160;&#160;&#160;&#160;&#160; where major_ID=OBJECT_ID(@Identifier)\n&#160;&#160;&#160;&#160;&#160; and class=7 and minor_ID&gt;0\n&#160;&#160;&#160;&#160;&#160; )f\n&#160;&#160;&#160;&#160;&#160; FOR XML PATH(''), TYPE).value('.', 'varchar(max)')&#160; \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; SELECT @Script=REPLACE(@Script,'|,|',',')+COALESCE(@PrimaryKeyBuild,'')+'\n) ON [PRIMARY]'+ Coalesce('\n\n\/* and the extended properties associated with the table and its indexes *\/'+ @ExtendedPropertiesBuild,'')&#160;&#160;&#160;&#160; \n\nEND\nSELECT COALESCE(@Script,'-- could not find '''+@identifier+''' in '+DB_NAME(),'null identifier.')\n&#160;&#160;&#160; AS Build_Script\nGO\nIF NOT EXISTS\n&#160; (SELECT 1 FROM sys.objects WHERE NAME = 'sp_ScriptFor' AND IS_MS_SHIPPED=1)\n&#160;&#160; EXEC sp_ms_marksystemobject 'sp_ScriptFor'\nGO\n&#160;\nGO \n<\/pre>\n<p>So all you need to do now is to collect up the other scripts you find useful and configure up your SSMS Query Shortcuts to give you extra speed for your database development work, especially if you are refactoring someone else&#8217;s database. The reason I like doing this sort of thing is because I like to hone my development environment to my own particular tastes. Your tastes will be different, but I hope you agree with the principle that it is good to take some time to make sure you can develop things quickly and without frustrating delays. There is nothing more frustrating than wrestling with an IDE designed by people who don&#8217;t seem to understand how database developers do their work.<\/p>\n<p class=\"note\">See also the first two articles in this series<br \/>&#160;&#160;&#160;&#160;&#160; <a href=\"http:\/\/www.simple-talk.com\/sql\/t-sql-programming\/finding-stuff-in-sql-server-database-ddl\/\">Finding Stuff in SQL Server Database DDL<\/a><br \/>&#160;&#160;&#160;&#160;&#160; <a href=\"http:\/\/www.simple-talk.com\/sql\/t-sql-programming\/exploring-your-database-schema-with-sql\/\">Exploring your database schema with SQL<\/a><\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Phil shows how to start squeezing powerful magic from SSMS for doing a detailed exploration of the metadata of your routines and tables, in this third part to his series on exploring your database schema with SQL.&hellip;<\/p>\n","protected":false},"author":154613,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143531],"tags":[4168,4150,4151,4252,4190],"coauthors":[],"class_list":["post-875","post","type-post","status-publish","format-standard","hentry","category-t-sql-programming-sql-server","tag-database","tag-sql","tag-sql-server","tag-t-sql-programming","tag-tsql"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/875","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/154613"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=875"}],"version-history":[{"count":5,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/875\/revisions"}],"predecessor-version":[{"id":92550,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/875\/revisions\/92550"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=875"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=875"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=875"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=875"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}