{"id":63883,"date":"2007-10-03T05:14:00","date_gmt":"2007-10-03T05:14:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2007\/10\/03\/hey-scripting-guy-how-can-i-retrieve-the-field-size-and-a-sample-record-for-all-the-tables-and-fields-in-an-office-access-database\/"},"modified":"2007-10-03T05:14:00","modified_gmt":"2007-10-03T05:14:00","slug":"hey-scripting-guy-how-can-i-retrieve-the-field-size-and-a-sample-record-for-all-the-tables-and-fields-in-an-office-access-database","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-retrieve-the-field-size-and-a-sample-record-for-all-the-tables-and-fields-in-an-office-access-database\/","title":{"rendered":"Hey, Scripting Guy! How Can I Retrieve the Field Size and a Sample Record For All the Tables and Fields in an Office Access Database?"},"content":{"rendered":"<p><H2><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\"> <\/H2>\n<P>I recently read an <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/jul07\/hey0709.mspx\"><B>article of yours<\/B><\/A> that showed me how I can retrieve the names of all the tables in an Access database, along with a list of all the fields in each table and the data type of each of those fields. That\u2019s a really useful script, but it would be even more useful if it could list the field size and also display a sample record for each table. Can you help me with that?<BR><BR>&#8212; SP<\/P><IMG border=\"0\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" height=\"5\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\"><A href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><IMG class=\"farGraphic\" title=\"Script Center\" border=\"0\" alt=\"Script Center\" align=\"right\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" height=\"288\"><\/A> \n<P>Hey, SP. You know, this might very well be the best day in the Scripting Guy who writes this column\u2019s entire life. Why is this such a great day? Well, awhile back the Scripting Guys began a new ritual in which they start off every morning by getting together and eating doughnuts. <\/P>\n<TABLE id=\"EBD\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. Does this help them build team morale? Is this a way for the Scripting Guys to find time to sit down and discuss future plans for the Script Center? To tell you the truth, it\u2019s mostly just an excuse to sit down and eat doughnuts.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>At any rate, the Scripting Guy who writes this column brought in the doughnuts this morning. (Come to think of it, the Scripting Guy who writes this column brings in the doughnuts <I>every<\/I> morning.) As it turned out, however, Scripting Guy Jean Ross needed to work from home today. What did that mean? You got it: the Scripting Guy who writes this column got to eat <I>both<\/I> doughnuts! And chocolate-covered ones, to boot!<\/P>\n<P>Could it get any better than that?<\/P>\n<P>Now, because he\u2019s <I>way<\/I> behind on his commitments for the duo\u2019s upcoming <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/topics\/teched07\/default.mspx\"><B>trip to Barcelona<\/B><\/A>, the Scripting Guy who writes this column originally toyed with the idea of <I>not<\/I> writing this column, at least not today. (His plan was to tell everyone that he <I>did<\/I> write it, but the Scripting Editor deleted it.) Two doughnuts later, however, he\u2019s in such a good mood that he decided, what the heck, let\u2019s do a column anyway. With that in mind, here\u2019s a script that can grab all the tables in an Access database; report back the name, data type, and size for each and every field in those tables; and then display a sample record for each table.<\/P>\n<TABLE id=\"EGE\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. Yes, that <I>is<\/I> a lot of work. Obviously the Scripting Guy who writes this column <I>needs<\/I> two doughnuts in order to keep up his strength.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>Here\u2019s the script:<\/P><PRE class=\"codeSample\">Const adSchemaTables = 20\nConst adSchemaColumns = 4<\/p>\n<p>Set objConnection = CreateObject(&#8220;ADODB.Connection&#8221;) \nSet objRecordSet2 = CreateObject(&#8220;ADODB.Recordset&#8221;)<\/p>\n<p>objConnection.Open _\n    &#8220;Provider = Microsoft.Jet.OLEDB.4.0; &#8221; &amp; _\n        &#8220;Data Source = &#8216;C:\\Scripts\\Test.mdb'&#8221;<\/p>\n<p>Set objRecordset = objConnection.OpenSchema(adSchemaTables)<\/p>\n<p>Do Until objRecordset.EOF\n    strSample = &#8220;&#8221;\n    strTableName = objRecordset(&#8220;Table_Name&#8221;)<\/p>\n<p>    If UCase(objRecordset(&#8220;Table_Type&#8221;)) = &#8220;TABLE&#8221; Then<\/p>\n<p>    Set objFieldSchema = objConnection.OpenSchema(adSchemaColumns, _\n        Array(Null, Null, strTableName))<\/p>\n<p>        Wscript.Echo &#8220;============================================================&#8221;\n        Wscript.Echo UCase(objRecordset(&#8220;Table_Name&#8221;))\n        Wscript.Echo &#8220;============================================================&#8221;\n        Wscript.Echo\n        objRecordset2.Open &#8220;SELECT * FROM &#8221; &amp; strTableName, objConnection\n        objRecordset2.MoveFirst<\/p>\n<p>        Do While Not objFieldSchema.EOF\n            strColumn = objFieldSchema(&#8220;Column_Name&#8221;)\n            Wscript.Echo &#8220;Field Name: &#8221; &amp; objFieldSchema(&#8220;Column_Name&#8221;) \n            Wscript.Echo &#8220;Data Type: &#8221; &amp; objFieldSchema(&#8220;Data_Type&#8221;)\n            Wscript.Echo &#8220;Field Size: &#8221; &amp; objFieldSchema(&#8220;Character_Maximum_Length&#8221;)\n            Wscript.Echo\n            strSample = strSample &amp; strColumn &amp; &#8221; &#8212; &#8221; &amp; _\n                objRecordset2.Fields.Item(strColumn) &amp; vbCrLf\n            objFieldSchema.MoveNext\n        Loop<\/p>\n<p>        Wscript.Echo\n        Wscript.Echo &#8220;SAMPLE RECORD&#8221;\n        Wscript.Echo strSample\n        Wscript.Echo\n        Wscript.Echo<\/p>\n<p>        objRecordset2.Close\n    End If<\/p>\n<p>    objRecordset.MoveNext\nLoop\n<\/PRE>\n<TABLE id=\"EZE\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P><B>Access 2007<\/B><B>:<\/B> If you\u2019re running this against an Access 2007 database, your Open statement will look a little different than the Open statement in this example. Not only is the file extension on the database file different (.accdb rather than .mdb) but the provider is a little different too:<\/P><PRE class=\"codeSample\">objConnection.Open _\n    &#8220;Provider = Microsoft.ACE.OLEDB.12.0; &#8221; &amp; _\n        &#8220;Data Source = C:\\Scripts\\Test.accdb&#8221;\n<\/PRE><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>We\u2019re not going to talk about the basic fundamentals behind retrieving table\/field information from an Access database; that \u2013 along with a fascinating discussion of \u201clifelogging\u201d \u2013 is covered in our <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/jul07\/hey0709.mspx\"><B>first article<\/B><\/A> on this subject. Besides, the Scripting Guy who writes this column is feeling a little sluggish all of a sudden; that in itself is reason enough to skip the fundamentals and, instead, concentrate on the code that distinguishes this script from our original script.<\/P>\n<TABLE id=\"EPF\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. Is the Scripting Guy who writes this column feeling a little sluggish because he ate too many doughnuts? Too many doughnuts?!? We don\u2019t even know what that question <I>means<\/I>!<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>As we did in our original script, we start this one out by defining a pair of constants (adSchemaTables and adSchemaColumns), constants that enable us to access the properties of the database\u2019s tables and fields, respectively. We then create an instance of the <B>ADODB.Connection<\/B> object, the object used to connect to a database, as well as an instance of the <B>ADODB.Recordset<\/B> object (an instance we named objRecordset2). What are we going to use <I>that<\/I> object for? We\u2019ll explain that in just a minute.<\/P>\n<P>From there we call the Connection object\u2019s <B>Open<\/B> method to open the database C:\\Scripts\\Test.mdb, then use the following line of code to return a recordset (objRecordset) containing information about all the tables found in Test.mdb:<\/P><PRE class=\"codeSample\">Set objRecordset = objConnection.OpenSchema(adSchemaTables)\n<\/PRE>\n<P>At this point, we get serious.<\/P>\n<P>Well, right after we eat another doughnut, that is.<\/P>\n<P>OK, <I>now<\/I> we get serious. Our first step is to set up a Do Until loop that runs until objRecordset\u2019s <B>EOF<\/B> (end-of-file) property is True. (In other words, a loop that runs until we\u2019ve finished looking at all the items in the recordset.) Inside this loop, we set the value of a variable named strSample to nothing, then assign the value of the <B>Table_Name<\/B> property (which, needless to say, is nothing more than the name of the table) to the variable strTableName.<\/P>\n<P>That brings us to this line of code:<\/P><PRE class=\"codeSample\">If UCase(objRecordset(&#8220;Table_Type&#8221;)) = &#8220;TABLE&#8221; Then\n<\/PRE>\n<P>To be honest, we threw this in just for the heck of it. By limiting our reported data to those tables that have a <B>Table_Type<\/B> equal to TABLE we end up only displaying information for the database tables that <I>we<\/I> created; any other tables (such as the various sundry Access system tables) are ignored. That seemed like a good idea to us; after all, 99% of the time (at least) these are the only tables you\u2019re interested in anyway.<\/P>\n<TABLE id=\"EFH\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. What about that other 1% of the time? No problem; just delete the If-Then statement and the End If statement and you\u2019ll get back information for <I>all<\/I> the tables in the database.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>Assuming we <I>do<\/I> have a user-created table we then call the <B>OpenSchema<\/B> method in order to return field-related information for the first table in the recordset:<\/P><PRE class=\"codeSample\">Set objFieldSchema = objConnection.OpenSchema(adSchemaColumns, _\n    Array(Null, Null, strTableName))\n<\/PRE>\n<P>We then use this block of code to write a \u201cheader\u201d to the screen:<\/P><PRE class=\"codeSample\">Wscript.Echo &#8220;============================================================&#8221;\nWscript.Echo UCase(objRecordset(&#8220;Table_Name&#8221;))\nWscript.Echo &#8220;============================================================&#8221;\nWscript.Echo\n<\/PRE>\n<P>As you can see, this is no big deal: it\u2019s just the table name (TABLE_NAME) bracketed by some equals sign, the better to make the name stand out and to separate one table from another. In other words, this gives us a header that looks like this:<\/P><PRE class=\"codeSample\">============================================================\nCOMPUTERS\n============================================================\n<\/PRE>\n<P>And then we have these two lines of code:<\/P><PRE class=\"codeSample\">objRecordset2.Open &#8220;SELECT * FROM &#8221; &amp; strTableName, objConnection\nobjRecordset2.MoveFirst\n<\/PRE>\n<P>What are <I>these<\/I> lines doing here? Well, we now know the name of each field in the table; that information is safely tucked away in the recordset objFieldSchema. However, the information in objFieldSchema only includes \u201cmetadata\u201d about the fields: it lists the field name, type, and size, but <I>not<\/I> the field value. We use the first line of code to create a regular old ADO recordset, one consisting of all data in the table strTableName. We then use the second line of code to move to the first record in the returned recordset. This first record is going to serve as the source of the sample record we want to display onscreen.<\/P>\n<P>From there we set up a second Do Until loop to loop through the field data stored in objFieldSchema. Inside that loop we echo back some basic information about each field, including the value of the field\u2019s <B>Character_Maximum_Length<\/B> property. And yes, as usual, you\u2019re way ahead of us; that <I>does<\/I> tell us the size of the field:<\/P><PRE class=\"codeSample\">Wscript.Echo &#8220;Field Size: &#8221; &amp; objFieldSchema(&#8220;Character_Maximum_Length&#8221;)\n<\/PRE>\n<TABLE id=\"EUAAC\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. We should point out that fields will only have a size if the underlying data type has a size. A field that can contain a maximum of 100 characters will report back a Character_Maximum_Length value of 100. A numeric field, by contrast, doesn\u2019t <I>have<\/I> a field size. Thus you\u2019ll get back, well, nothing.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>After that we use this line of code to store the field name, as well as the actual field value for the first record in the table, in the variable strSample:<\/P><PRE class=\"codeSample\">strSample = strSample &amp; strColumn &amp; &#8221; &#8212; &#8221; &amp; _\n    objRecordset2.Fields.Item(strColumn) &amp; vbCrLf\n<\/PRE>\n<P>See what we\u2019re doing? Suppose the first field in the first table is named ComputerName, and the first record in the table has the value atl-ws-01. That means that, at the moment anyway, strSample will be equal to this:<\/P><PRE class=\"codeSample\">ComputerName &#8212; atl-ws-01\n<\/PRE>\n<P>And then we loop around and repeat the process with the next field in the table, adding the field name (and sample value) to strSample. After we\u2019ve looped through all the fields in the table we echo back the value of strSample, close objRecordset2, and then go back and do this all over again with the second table in the database.<\/P>\n<P>When all is said and done, we\u2019ll have a report similar to this:<\/P><PRE class=\"codeSample\">============================================================\nCOMPUTERS\n============================================================<\/p>\n<p>Field Name: ComputerName\nData Type: 130\nField Size: 50<\/p>\n<p>Field Name: SerialNumber\nData Type: 130\nField Size: 50<\/p>\n<p>SAMPLE RECORD\nComputerName &#8212; atl-ws-01\nSerialNumber &#8212; 1<\/p>\n<p>============================================================\nDISKDRIVES\n============================================================<\/p>\n<p>Field Name: Drive\nData Type: 130\nField Size: 50<\/p>\n<p>Field Name: DriveSize\nData Type: 2\nField Size:<\/p>\n<p>Field Name: SerialNumber\nData Type: 130\nField Size: 50<\/p>\n<p>Field Name: Type\nData Type: 130\nField Size: 50<\/p>\n<p>SAMPLE RECORD\nDrive &#8212; C:\nDriveSize &#8212; 50\nSerialNumber &#8212; 1\nType &#8212;\n<\/PRE>\n<P>Yes, <I>very<\/I> exciting.<\/P>\n<P>We hope that answers your question, SP. And Scripting Guy Jean Ross, if you happen to be reading this, well, don\u2019t worry about the rest of the team: if you want to work at home tomorrow that\u2019s fine with us. In fact, feel free to work at home as often as you wish; whatever\u2019s easiest \u2013 and best \u2013 for, uh, you.<\/P>\n<P>Now, where did that last maple bar wander off to \u2026.<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I recently read an article of yours that showed me how I can retrieve the names of all the tables in an Access database, along with a list of all the fields in each table and the data type of each of those fields. That\u2019s a really useful script, but it would be even more [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[54,49,3,5],"class_list":["post-63883","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-microsoft-access","tag-office","tag-scripting-guy","tag-vbscript"],"acf":[],"blog_post_summary":"<p>I recently read an article of yours that showed me how I can retrieve the names of all the tables in an Access database, along with a list of all the fields in each table and the data type of each of those fields. That\u2019s a really useful script, but it would be even more [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/63883","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=63883"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/63883\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=63883"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=63883"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=63883"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}