{"id":65473,"date":"2007-02-21T00:58:00","date_gmt":"2007-02-21T00:58:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2007\/02\/21\/how-can-i-use-a-blank-row-to-separate-data-in-an-excel-spreadsheet\/"},"modified":"2007-02-21T00:58:00","modified_gmt":"2007-02-21T00:58:00","slug":"how-can-i-use-a-blank-row-to-separate-data-in-an-excel-spreadsheet","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/how-can-i-use-a-blank-row-to-separate-data-in-an-excel-spreadsheet\/","title":{"rendered":"How Can I Use a Blank Row to Separate Data in an Excel Spreadsheet?"},"content":{"rendered":"<p><H2><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" height=\"34\" alt=\"Hey, Scripting Guy! Question\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"> <\/H2>\n<P>Hey, Scripting Guy! How can I use a blank row to separate rows of data in a Microsoft Excel spreadsheet?<BR><BR>&#8212; AR<\/P><IMG height=\"5\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" border=\"0\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" height=\"34\" alt=\"Hey, Scripting Guy! Answer\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"><A href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><IMG class=\"farGraphic\" title=\"Script Center\" height=\"288\" alt=\"Script Center\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" align=\"right\" border=\"0\"><\/A> \n<P>Hey, AR. You know, most people believe that the Scripting Guys all think alike, that we always agree on everything. That\u2019s not true, though; instead, like any other team, we disagree from time-to-time. Sure, the team would be best-served by always agreeing with Greg, but for some strange reason we don\u2019t.<\/P>\n<P>Take, for example, the question of which is the best sport in the world. Peter Costantini, our resident bon vivant, would undoubtedly argue that soccer is the best sport in the world. Dean Tsaltas, Canadian-born and bred, would likely vote for hockey. (Of course, \u201chockey\u201d is Dean\u2019s answer to pretty much any question that comes up.) Jean Ross \u2013 well, Jean Ross thinks that <I>car racing<\/I> is a sport, which means that there\u2019s no reason to consider her opinion, at least not on this question. <\/P>\n<P>As it turns out, though, those three Scripting Guys are all wrong. The best sport in the world, and the truest test of athletic prowess, is this: miniature golf.<\/P>\n<P>Yes, miniature golf, the sport of champions. And no, this has nothing to do with the fact that the Scripting Dad and Scripting Son squared off in miniature golf this past weekend; the Scripting Guy who writes this column has always believed miniature golf was the most grueling and most demanding of all sports. The fact that he shot a 61 \u2013 11 under a par \u2013 and beat the Scripting Son by 13 strokes is totally irrelevant.<\/P>\n<P>Although it does prove, once again, that the Scripting Dad is <I>way<\/I> better than the Scripting Son at anything sports-related.<\/P>\n<P>Weight-lifting? Well, sure, the Scripting Son can bench press more than the Scripting Dad, but weight-lifting doesn\u2019t seem all that sporting-like. Long-distance running? Come on, this is the age of the automobile; no one runs anymore. Throwing a ball harder, farther, and more accurately? Oh, please; name one sport in which throwing a ball hard, far, and accurately matters.<\/P>\n<P>OK, fine. But the Scripting Dad <I>still<\/I> won the miniature golf showdown. Not only that, but he can write a script that uses a blank row to separate rows of data in a Microsoft Excel spreadsheet:<\/P><PRE class=\"codeSample\">Const xlShiftDown = -4121<\/p>\n<p>Set objExcel = CreateObject(&#8220;Excel.Application&#8221;)\nobjExcel.Visible = True\nSet objWorkbook = objExcel.Workbooks.Open(&#8220;C:\\Scripts\\Test.xls&#8221;)\nSet objWorksheet = objWorkbook.Worksheets(1)<\/p>\n<p>i = 1<\/p>\n<p>strStartValue = Left(objExcel.Cells(i, 1), 1)<\/p>\n<p>Do Until objExcel.Cells(i, 1) = &#8220;&#8221;\n    strValue = Left(objExcel.Cells(i, 1), 1)\n    If strValue &lt;&gt; strStartValue Then\n        Set objRange = objExcel.Cells(i,1).EntireRow\n        objRange.Activate\n        objRange.Insert xlShiftDown\n        strStartValue = Left(objExcel.Cells(i + 1, 1), 1)\n    End If\n    i = i + 1\nLoop\n<\/PRE>\n<P>Before we talk about how this script works we need to explain what AR\u2019s spreadsheet looks like. AR has a spreadsheet that looks something like this:<\/P><IMG height=\"402\" alt=\"Microsoft Excel\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/blankrow1.jpg\" width=\"287\" border=\"0\"> \n<P><BR>As you can see, in this spreadsheet there are five different users (listed in column A):<\/P>\n<TABLE class=\"\" cellSpacing=\"0\" cellPadding=\"0\" border=\"0\">\n<TBODY>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>A Person<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>B Person<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>C Person<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>D Person<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>E Person<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<P>The spreadsheet contains one or more rows of data for each of these users; for example, user A Person has data listed in the first three rows. What AR would like to do is insert a blank row between the data for A Person and the data for B Person, eventually ending up with a spreadsheet that looks like this:<\/P><IMG height=\"471\" alt=\"Microsoft Excel\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/blankrow2.jpg\" width=\"318\" border=\"0\"> \n<P><BR>But how in the world are we supposed to do that?<\/P>\n<P>Well, to begin with, we create a constant named xlShiftDown and set the value to -4121; we\u2019ll use this constant to tell Excel to shift cells down any time we insert a new, blank row. (If we were working with columns, we could use the constant xlShiftRight, with a value of -4161, to move cells to the right.) We then use this block of code to create a running instance of Excel that we can see onscreen, and to open the file C:\\Scripts\\Test.xls:<\/P><PRE class=\"codeSample\">Set objExcel = CreateObject(&#8220;Excel.Application&#8221;)\nobjExcel.Visible = True\nSet objWorkbook = objExcel.Workbooks.Open(&#8220;C:\\Scripts\\Test.xls&#8221;)\nSet objWorksheet = objWorkbook.Worksheets(1)\n<\/PRE>\n<P>Now comes the fun part. To begin with, we assign the value 1 to a counter variable named <I>i<\/I>; we\u2019ll use this variable to keep track of our position in the spreadsheet. We then use this line of code to grab the first character in cell 1,1 and store it in a variable named strStartValue:<\/P><PRE class=\"codeSample\">strStartValue = Left(objExcel.Cells(i, 1), 1)\n<\/PRE>\n<TABLE class=\"dataTable\" id=\"ESE\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note<\/B>. In case you\u2019re wondering, <B>objExcel.Cells(i, 1) <\/B>gives us the value of cell A1 (row 1, column 1). We then use the <B>Left<\/B> function to grab just the first character in that value.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>The tricky part here is knowing when to insert a blank row; after all, we want to insert a blank row only when we\u2019re done with one user\u2019s data and are moving on to another user\u2019s data. (Needless to say, this script isn\u2019t going to work very well unless the spreadsheet has been sorted by user name. For a programmatic way to sort data take a look at this <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/officetips\/jul05\/tips0719.mspx\"><B>Office Space article<\/B><\/A>.) How will we figure out when we\u2019re finished with the data for our first user, A Person? Well, we\u2019re going to do that by storing the user data found in the first row in strStartValue, then looking one row ahead to see if the data in <I>that<\/I> row matches. If it does, then we know we\u2019re still working with A Person. If it doesn\u2019t, that means we\u2019re now working with a new user.<\/P>\n<P>Don\u2019t worry; that should make a little more sense as we walk through the script.<\/P>\n<P>To get things rolling, we set up a Do Until loop designed to loop until we encounter a blank cell in column A:<\/P><PRE class=\"codeSample\">Do Until objExcel.Cells(i, 1) = &#8220;&#8221;\n<\/PRE>\n<P>Inside that loop, the first thing we do is grab the initial character in the current row and store it in a variable named strValue:<\/P><PRE class=\"codeSample\">strValue = Left(objExcel.Cells(i, 1), 1)\n<\/PRE>\n<P>We now have the first character in cell A1 stored in two different variables: strStartValue and strValue. Our next step is to compare these two values and see if they are different:<\/P><PRE class=\"codeSample\">If strValue &lt;&gt; strStartValue Then\n<\/PRE>\n<P>The first time through the loop the values are <I>not<\/I> different; both strStartValue and strValue are equal to <I>A<\/I>. Therefore, we skip the If Then statement, increment the value of i by 1, then loop around and repeat the process with the second row in the spreadsheet. The important thing to note here is that we did <I>not<\/I> change the value of strStartValue. That variable still holds the letter <I>A<\/I>, the first character in cell A1. Because we incremented the value of i by 1, however, strValue will now be equal to the first character from cell A2. <\/P>\n<P>See how that works? Good. Now let\u2019s move on.<\/P>\n<P>Sooner or later we\u2019re going to find a discrepancy between strStartValue and strValue; notice that the first character in cell A4 is a <I>B<\/I>. What happens when strStartValue and strValue no longer match? This happens:<\/P><PRE class=\"codeSample\">Set objRange = objExcel.Cells(i,1).EntireRow\nobjRange.Activate\nobjRange.Insert xlShiftDown\nstrStartValue = Left(objExcel.Cells(i + 1, 1), 1)\n<\/PRE>\n<P>In the first line of code we\u2019re creating a Range object that encompasses all of row 4; we do that by specifying cell A4 (<B>objExcel.Cells(i, 1)<\/B> and then referencing the <B>EntireRow<\/B> property. We then use the <B>Activate<\/B> method to make this the active row in the spreadsheet:<\/P><PRE class=\"codeSample\">objRange.Activate\n<\/PRE>\n<P>Basically what we\u2019ve done here is moved the cursor down to cell A4 and then selected the entire row. With the row selected we use the <B>Insert<\/B> method to insert a blank row, using the parameter xlShiftDown to shift the existing cells down. What does that mean? That means that the data currently in row 4 will be shifted down to row 5, and row 4 will become a blank row.<\/P>\n<P>Which is exactly what we wanted to happen.<\/P>\n<P>We then use this line of code to grab the first character in row <I>5<\/I> (i + 1) and store that data in strStartValue:<\/P><PRE class=\"codeSample\">strStartValue = Left(objExcel.Cells(i + 1, 1), 1)\n<\/PRE>\n<P>That makes strStartValue equal to <I>B<\/I>.<\/P>\n<P>We then increment the value of i by 1, loop around, and start the process all over again. Granted, it\u2019s a bit confusing. But it works. Give it a try and you\u2019ll see.<\/P>\n<P>Incidentally, the more we think about it the more we\u2019re wondering if miniature golf really <I>is<\/I> the best sport in the world. For one thing, it cost the Scripting Dad $16 for he and the Scripting Son to play. For another, what did the Scripting Dad get for winning? You got it: nothing. <\/P>\n<P>Now, compare that to, oh, say, the <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/default.mspx\"><B>2007 Winter Scripting Games<\/B><\/A>. How much will cost you to enter the Scripting Games? Zilch; the Scripting Games are always free to everyone. And what do you get if you win? Well, how about a <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/games07\/bobble.mspx\"><B>Dr. Scripto Bobblehead doll<\/B><\/A> or a copy of the book <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/topics\/msh\/payette1.mspx\"><B>Windows PowerShell in Action<\/B><\/A>? Not bad, huh? You know, come to think of it, maybe the <I>Winter Scripting Games<\/I> are the best sport in the entire world.<\/P>\n<P>Well, unless it turns out that the Scripting Son actually <I>can<\/I> write scripts better than the Scripting Dad. In that case, we\u2019ll go back to miniature golf as being the best sport in the world.<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! How can I use a blank row to separate rows of data in a Microsoft Excel spreadsheet?&#8212; AR Hey, AR. You know, most people believe that the Scripting Guys all think alike, that we always agree on everything. That\u2019s not true, though; instead, like any other team, we disagree from time-to-time. Sure, [&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":[48,49,3,5],"class_list":["post-65473","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-microsoft-excel","tag-office","tag-scripting-guy","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! How can I use a blank row to separate rows of data in a Microsoft Excel spreadsheet?&#8212; AR Hey, AR. You know, most people believe that the Scripting Guys all think alike, that we always agree on everything. That\u2019s not true, though; instead, like any other team, we disagree from time-to-time. Sure, [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/65473","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=65473"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/65473\/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=65473"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=65473"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=65473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}