#1
|
|||
|
|||
Populate Column 1 with data from cells in Column 2 based on data contained in Column 3
I'm new to writing macros. I came up with an idea for an export and was hoping someone could assist in how to automate. I've provided an attachment of a very generic mock export with a second tab containing what I want it to look like after I run the macro.
Background: I produce exports from MS Project which provides a list of my tasks and summary tasks presented as it appears on the tab 'Export'. However, for the purposes of this export I am to perform frequently- I want to take the Summary Tasks out of the 'Task Name' column and populate in a new column. I need the program to recognize where to put the data based on information contained in Column F (View Filter). Steps: First step is: Insert a column between B and C and title it "Sub-Phase". (I can write this part) Second step: Find any row containing "Phase" in Column G (View filter) and delete. (I can also write this) Third step: Find "Sub-Phase" in Column G and copy the contents of D#(whatever row # Sub-Phase is contained in) and paste down in column C until the cell just before the next Sub-Phase. Step 4: Find all rows containing "Sub-Phase" and delete. (I can also write this) The finished product should look like the tab I titled "End Result" Your help is much appreciated! Thanks E Last edited by EC37; 07-15-2014 at 08:41 AM. Reason: identifying steps I can write myself |
#2
|
||||
|
||||
The way you describe this, E, it isn't the basic statements that bother you but the structure; you're not sure how to go about it. Now, the way I'd go about it may not be the way you would. In programming there are always a lot of ways to do a task. But here's how I'd structure the logic, written not in VBA but in pseudo-code:
Code:
'I don't trust myself not to make mistakes. copy the "Export" worksheet to a new one, and switch to the new sheet for all subsequent commands. insert new column at C and title it "Sub-Phase". rz = the last row '14 in your case for jr = 2 to rz select case value-in-column-G 'was col F in original worksheet case "Phase" do nothing just yet case "Sub-Phase" save value from col D case else set col C to the saved value end select next jr ' Now delete the rows you no longer want. for jr 1 rz to 2 step -1 select case value-in-col-G case "Phase": Delete row case "Sub-Phase": Delete row case else: 'no action end select next jr |
#3
|
|||
|
|||
lol. super fast response time to the private message I just sent you to enlist your help...
I had similar thoughts on how to write it- but of course was using only what I know (such as Copy & Paste). I didn't realize you save the value and then set the value to a new column. My other thought was what you had shown me previously on how to Group specific rows based on "Phase" and "Sub-Phase". Such as: Code:
ez = Range("M1").End(xlDown).Row Dim eStart, eEnd eEnd = 1 Do eStart = StartRow1(eEnd, "Phase", ez) If eStart = 0 Then Exit Do eEnd = EndRow1(eStart, ez) Range(eStart & ":" & eEnd).Group Loop Yes, details would be helpful. But no, it is not obvious as to why you are doing the second look backward- hoping you could explain. |
#4
|
||||
|
||||
I'm not sure from what you wrote whether you know this already, but the most obvious way to save a value and use it later is to set a variable of your own, perhaps like this:
Code:
For jr = 2 To rz Select Case ows.Cells(jr, 7).Value Case "Phase" Case "Sub-Phase" col4 = ows.Cells(jr, 4).Value Case Else ows.Cells(jr, 3).Value = col4 End Select Next jr "Group!" (he says thoughtfully); I didn't think of applying that here. (Pause to think about it a while.) But no, the problem with grouping is that what you really want is to copy the Sub-Phase value in D to the lower level in a new column; grouping won't help you with that. Interesting thought, though; I'll have to keep it in mind for other tasks where it might not ordinarily have occurred to me. |
#5
|
||||
|
||||
The reason I did the second loop backward is easy to miss at first. Consider what happens if we do the loop the normal way, like this:
Code:
For jr = 1 to 6 If ows.Cells(jr, 7).Value = "Phase" then ows.Rows(jr).Delete Next jr 1) jr is set to 1 2) Checks G1; it's not "Phase", so it skips to the next record 3) jr is now 2 4) Checks G2; it's equal to "Phase", so it deletes row 2. 5) jr is now 3. 6) Checks G3... But wait! We just deleted row 2; so what was row 3 a moment ago is row 2 now, and row 4 is now row 3, and so on. So when I check row 3 (because jr is now 3), I skipped a row. G3—what was originally G3 but is now G2—has "Phase", but the above logic never looks at it. There's more than one way to get around that. My way is usually to run the loop backward, like this: Code:
For jr = 6 to 1 Step -1 If ows.Cells(jr, 7).Value = "Phase" then ows.Rows(jr).Delete Next jr Code:
For jr = 1 to 6 If ows.Cells(jr, 7).Value = "Phase" Then ows.Rows(jr).Delete jr = jr - 1 End If Next jr And the fact that I had to do the loop backward is why I had to have two loops in the first place. Until I noticed the above problem, I had a nice simple bit of logic with one loop, doing everything in one pass. Oh, well. |
#6
|
|||
|
|||
The mentioning of the 'Group' code I provided, was just the idea of using that set up (perhaps replacing ".Group" with ".Copy" or ".Paste") was how I was originally going about this when I tried to figure it out for myself. But I knew I needed to edit the StartRow and EndRow to be Cells, or something. Of course your way of simply using Select Case works just as well.
Now the code you provide in your first reply this morning, you wrote: Code:
Select Case ows.Cells(jr, 7).Value |
#7
|
||||
|
||||
"ows" is just my own idiosyncratic way of naming a worksheet. Most programmers learn eventually to use more descriptive variable names that just 'i' and 'j', 'x' and 'y'; eventually they start naming things "RetailWorksheet", "MonthlySum" and so forth.
Now, like them I've learned that there's a risk of making a name so cryptic that six months later I've forgotten what it's for and have difficulty understanding my own code. But I still hate my variable names to be too long; it makes for longer statements, more typing and perhaps other sins that I've forgotten just now. So I still make my names a lot shorter than most folks do; I just pack more information into fewer characters. I long ago gave up using one-character variable names, for reasons that even some experienced programmers will disagree with. So instead of using 'i', 'j', 'k' and so forth, as is traditional for loop indices, I use 'j' plus another character, eg "jr" for rows or "jl" for "list number", whatever strikes my fancy at the time. For objects I'm currently trying to use 'o' as the starting character, then another character or two to indicate what kind of object. "ows" means "worksheet" to me; "owb" is a workbook, "oc" is a cell, "org" is a range and so on. These names evolve from time to time; in fact until very recently I used "wso", "co" etc. When I need to distinguish between more than one cell, worksheet or whatever, I add a few letters; owsFm and owsTo, for example, when I'm transferring data from one worksheet to another, or rA and rZ for first and last rows. But when I'm working with just one object of its type at a time, as in this case, I'm content to start a program like this: Code:
Set owb = ThisWorkbook Set ows = ActiveSheet And by the way all this idiosyncrasy is for my own programs. Whenever I write a program for a client, that someone else may have to maintain next year after I'm gone, then it's all out the window and I must choose names that are likely to mean something more generally, not just in my own personal code. |
#8
|
|||
|
|||
Bob,
Your logic is a good ideal. I usually use the first initial of the worksheet name. IE: If I have a sheet called Result the I use "Rws". As for the workbook I may use a couple of characters. Such as in a program I'm currently working on "HykeShop" I name it "Hykwb". |
#9
|
|||
|
|||
Awesome. Well. I set the ows to be ActiveSheet as you mentioned. It worked, technically speaking
What happened at the end though, was it took the value of F# (F being the task name, and # being the row # that contains "Sub-Phase") and applied it from row 24 to 248- when it should have applied it from 24 and stopped at 31 (the famous .End(xlDown)). well, that's because I never set it to stop at the last row. So, I fixed that, and also determined another flaw I wasn't paying attention to- and that is: Some Phases have no Sub-Phases, therefore, the Phase name should be copied down. So instead of saying: Code:
Select Case ows.Cells(jr, 16).Value Case "Phase" Case "Sub-Phase" ows.Cells(jr, 5).Value = col6 etc... Code:
For jr = 2 To ec.Row Select Case ows.Cells(jr, 16).Value Case "Sub-Phase" col6 = ows.Cells(jr, 6).Value Case "Phase" col6 = ows.Cells(jr, 6).Value Case Else ows.Cells(jr, 5).Value = col6 End Select Next jr Last edited by EC37; 07-17-2014 at 08:52 AM. Reason: new troubles with phase included in the equasion. texttocolumns no longer an issue |
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Can I pre-populate cells with a formula? | Box | Excel | 1 | 05-03-2014 11:55 PM |
How to populate cells in Sheet2 with Data Source query using cell data from Sheet1 | bobznkazoo | Excel | 2 | 03-27-2014 11:14 AM |
How-TO format cells (FILL) by comparing cells | zanat0s | Excel | 1 | 07-03-2012 04:27 AM |
Count range cells eliminating merge cells | danbenedek | Excel | 0 | 06-15-2010 12:40 AM |
Populate cells in Word from a database | hotlilshan | Word | 3 | 12-09-2008 01:51 PM |