I have looked at similar questions but they don't seem to fit my problem. I have two sheets in excel; one has a type of header/overview data for some tasks, the other has several lines of details for each task.
I need help writing a macro that will match the Task ID between the two sheets and copy the entire row of header data from sheet one into a blank row above the group of detail rows in sheet two.
(Before this code will run, I will run a macro that will insert a blank line between each group of detail data. When I get this working, I will combine the two pieces of code.)
The copy statement is where I am stuck. It returns Application defined or object-defined error.
Sub InsertMWITitles()
‘copies the MWI titles above the correct MWI Steps group
Dim lngLastRowSht1, lngLastRowSht2, counterSht1, counterSht2As Long
With Worksheets(“MWI Titles”)
lngLastRowSht1 = .Cells(.Rows.Count, 8).End(xlUp).Row
lngLastRowSht2 = Worksheets(“MWI Steps”).Cells(Worksheets(“MWI Steps”).Rows.Count, 1).End(xlUp).Row
For counterSht1 = 1 To lngLastRowSht1
For counterSht2 = 1 To lngLastRowSht2
‘if the Task ID in column H of the MWI Titles sheet matches the Element ID in column A of
‘the MWI Steps sheet, copy the entire title row to the steps sheet above the group
If Worksheets(“MWI Titles”).Range("H" & (counterSht1)).Value = Sheets(2).Range("A" & counterSht2).Value Then
Worksheets(“MWI Titles”).Range("A" & (counterSht2).EntireRow.Copy Sheets(“MWI Steps”).Range("A" & (counterSht2 – 1))
End If
Next counterSht2
Next counterSht1
End With
End Sub
I also tried to copy and insert with shift down, but couldn't get that to work either.
The top section of the sample data is sheet 1/MWI Titles (the header data) and the bottom section is sheet 2 /MWI Steps (the detail data).
Sample of data in both sheets
I have an Excel spreadsheet with over 60 columns. Each column contains data from a SharePoint survey. The column headers are the actual survey questions that have been imported from a SharePoint data connection. I'm trying to do several things here.
First, I want to copy each column to a new worksheet. (The reason I need to do this is so that I can add the data in each column to a PowerPivot Data Model. PowerPivot recognizes the entire worksheet as one table, so it won't let me select only "Column A" to add to the Data Model, it automatically adds the entire table with all 60 columns).
Since I don't want to manually add 60 new sheets first before this, I'd like the code to copy each column to a newly created worksheet. (the worksheets don't need to be named, I could do that manually, unless someone has an easy way to do this as well!)
Then, I'd like the code to loop through each column performing the copy and paste to the newly created sheet.
I've found some examples of the code here for several related topics, but I'm so new to VBA that I'm having a hard time putting it all together. Thank you all so much for your time!
I've tried the following which does copy it over, but I'm not sure how to add a new sheet and loop through the columns
Sub CopyColumnToNewSheet()
Dim lastRow As Long
lastRow = Sheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
Sheets("Sheet2").Range("A1:A" & lastRow).Value = Sheets("Sheet1").Range("A1:A" & lastRow).Value
End Sub
You should do this instead, please note, there is no error handling, suit to your needs
Sub CopyColumnToNewSheet()
Const MySourcheSheetName = "Sheet1"
Dim CounterColumn As Long
For CounterColumn = 1 To Sheets(MySourcheSheetName).Cells.SpecialCells(xlCellTypeLastCell).Column
Sheets.Add
ActiveSheet.Name = Sheets(MySourcheSheetName).Cells(1, CounterColumn).Value 'ideally the title is unique and it's in the first row of each column
Sheets(MySourcheSheetName).Columns(CounterColumn).Copy Destination:=ActiveSheet.Columns(1)
Next CounterColumn
End Sub
I have two worksheets within the same workbook, namely sheet1 ("rawdata") and sheet2 ("Overview).
I copy downloaded data into sheet1 ("rawdata"). Here the number of rows vary but heading/columns are always the same. After this I need to copy specific cells into another worksheet.
Here are the "rules" I was thinking about:
1) Always copy cells from the rawdata sheet E9, W9, X9 and Y9 into a specific cell in the target sheet. I had something like this (which worked):
Worksheets("overview").Range("X10").Value = Worksheets("rawdata").Range("E9").Value
2) Always copy the value within column E in the lastrow. However, the last row is varying from rawdata to rawdata while the column (E) stays the same. I tried something like this: (not working)
....= Worksheets("rawdata").Range("E1").End(xlDown).Value
3) The script should be linked to the button, when I click the button again to insert the data from the sheet rawdata, the data should be inserted in the next (following) column of worksheet overview.
Assumes column E always has data. Which in this case should be true.
Sorry tried to simplify and broke it.
LastRow_WithDataInColumnE = Worksheets("rawdata").Range("E" & .Rows.Count).End(xlUp).Row
Should be
With Worksheets("rawdata")
LastRow_WithDataInColumnE = .Range("E" & .Rows.Count).End(xlUp).Row
End With
Now .Rows.Count should refer to Worksheets("rawdata")
Worksheets("overview").Range("X10").Value = Worksheets("rawdata").Range("E" & .Rows.Count).End(xlUp).Row.Value
Should be
With Worksheets("rawdata")
Worksheets("overview").Range("X10").Value = .Range("E" & .Rows.Count).End(xlUp).Row.Value
End With
There is a discussion here Error in finding last used cell in VBA. Suggests a better solution for situations where there is no data in Column E or where rows have been deleted.
You could do something like this to get the last data range in column E:
Public Function FindLastColumnECellAvailable()
FindLastColumnECellAvailable = "E" & WorksheetFunction.CountA(Range("E:E"))
End Function
Then you will have this:
At the end just read the cell value:
Range(FindLastColumnECellAvailable).Value
Greetings
Sorry
An apologize "in advance", I just read the date, hope this will help you yet or anyone else, it's my second day
I'm in a bad spot - any help pointing me in the right direction would be helpful and much appreciated.
I've created a Access process that copies an excel file and updates it with data from 2 record sets using Copy Recordset. The process now creates 39 workbooks by copying a 'template workbook' to a new file. Each workbook will contain at least one tab, but generally contain more, one workbook has over 20 tabs.
This is all done in Access. It copies the 'template' file and then runs a loop, and using Copy Recordset copies the 'template' worksheet to each tab.
After adding the tab, it loads the data from 2 record sets into the sheet. The 1st recordset loads one row of data - no problem. However the second loads multiple rows - which can vary in number.
This all works fine. The problem is formatting columns D through G.
If Column C = Revenue, Cost or Gross Margin (GM) I want that row's columns D through G formatted as currency.
If Column C = GM% then I want columns D through G formatted as a percentage.
If column C = Hours I don't have to format it.
What I would like is to create a function that formats these columns/rows based on Column C value, when the workbook is opened. I know there is an event that fires when the workbook is opened, and I know I have looped through all of the tabs in a workbook, o I'd want to run that function for each tab.
There may be one other issue - I think I can fix that in Access, but the EAC column is being exported as text and it should numeric. Not sure right now if that's being exported as Text - or EXCEL sees it as text.
Any help would be greatly appreciated. Thanks in advance.
I have images - but it won't let me post them just yet. If they would help - let me know, I'll try to email them to you.
Bob
I've come up with a way to do it, I've included the code.
However there may be a better way - so I'm open to suggestions.
Public Sub FormatTaskRows()
Dim Sheet As Object
Dim rngTasks As Range
Dim rngFCells As Range
Dim strTaskEnd As String
Dim ix As Integer
For Each Sheet In Sheets
If Sheet.Name = "Template" Then
Sheet.Visible = xlSheetVeryHidden
Else
Sheet.Visible = xlSheetVisible
Sheet.Activate
strTaskEnd = Range("C44").End(xlDown).Address
Set rngTasks = Range("$C$44:" & strTaskEnd)
'For Each Row In rngTasks
For ix = 1 To rngTasks.Rows.Count
Sheet.Unprotect
If rngTasks.Cells(ix) = "Revenue" Or rngTasks.Cells(ix) = "Cost" Or rngTasks.Cells(ix) = "Gross Margin (GM)" Then
Set rngFCells = Range(ActiveSheet.Name & "!D" & ix + 43 & ":G" & ix + 43)
rngFCells.Select
Selection.NumberFormat = "$#,##0.00"
Else
If rngTasks.Cells(ix) = "GM%" Then
Set rngFCells = Range(ActiveSheet.Name & "!D" & ix + 43 & ":G" & ix + 43)
rngFCells.Select
Selection.NumberFormat = "0.0000%"
End If
End If
Sheet.Protect
Next ix
End If
Next
End Sub
I have a row of data as follows:
header1 header2 header3 header4 header5
row key datavalue1 datavalue2 datavalue3 datavalue4 datavalue5....
so basically, I have a denormalized data set where the datavalues may or may not be empty on a row-by-row basis. I need to normalize them.
ie
12345678 NULL 10 3 NULL 14
would become:
12345678 header2 10
12345678 header3 3
12345678 header5 14
I could do this by using a paste special transform, but I have thousands of rows and I'd need to make sure that I get the right row key for each. furthermore, each row has a bunch of descriptives associated with it that I need copied over with each datavalue.
What is the easiest way to convert each row of columns such that I have multiple rows of a single column with all non-empty datavalues plus the associated datavalue reference? I need to be able to pivot the dataset.
If you have five "header" columns, enter these formulas
H1: =OFFSET($A$1,INT((ROW()-1)/5)+1,0)
I1: =OFFSET($A$1,0,IF(MOD(ROW(),5)=0,5,MOD(ROW(),5)))
J1: =INDEX($A$1:$F$9,MATCH(H1,$A$1:$A$9,FALSE),MATCH(I1,$A$1:$F$1,FALSE))
Copy H1:J?? and paste special values over the top. Sort on column J and delete anything that's a zero. If you have legitmate zeros in the data, then you first need to replace blank cells with some unique string that you can then delete later.
If you have more columns, then replace the '5' in all the above formulas with whatever number you have.
Seems to me that part of what you are trying to do is to "de-pivot" a pivot table. I've found this tip to be a tremendous help when I've had to do similar tasks: http://spreadsheetpage.com/index.php/tip/creating_a_database_table_from_a_summary_table/
Note that in Excel 2007, you can get to the old Excel 2003 pivot table wizard using the keystrokes Alt+D, P .
Excel has a transpose feature which may address your needs. It's pretty hidden and a bit clumsy but likely easier than delving into VBA. Here's an excerpt from Excel 2007 Help:
Blockquote
Switch (transpose) columns and rows
Show AllHide All
If data is entered in columns or rows, but you want to rearrange that data into rows or columns instead, you can quickly transpose the data from one to the other.
For example, the regional sales data that is organized in columns appears in rows after transposing the data, as shown in the following graphics.
1.On the worksheet, do the following:
To rearrange data from columns to rows, select the cells in the columns that contain the data.
To rearrange data from rows to columns, select the cells in the rows that contain the data.
2.On the Home tab, in the Clipboard group, click Copy .
Keyboard shortcut To copy the selected data, you can also press CTRL+C.
Note You can only use the Copy command to rearrange the data. To complete this procedure successfully, do not use the Cut command.
3.On the worksheet, select the first cell of the destination rows or columns into which you want to rearrange the copied data.
Note Copy areas (copy area: The cells that you copy when you want to paste data into another location. After you copy cells, a moving border appears around them to indicate that they've been copied.) and paste areas (paste area: The target destination for data that's been cut or copied by using the Office Clipboard.) cannot overlap. Make sure that you select a cell in a paste area that falls outside of the area from which you copied the data.
4.On the Home tab, in the Clipboard group, click the arrow below Paste, and then click Transpose.
5.After the data is transposed successfully, you can delete the data in the copy area.
Tip If the cells that you transpose contain formulas, the formulas are transposed and cell references to data in transposed cells are automatically adjusted. To make sure that formulas continue to refer correctly to data in nontransposed cells, use absolute references in the formulas before you transpose them.
For more information, see Switch between relative, absolute, and mixed references.
Blockquote
Let's look at a possible solution in VBA. I think this will really help. Here are a few things you should know about my code.
You'll need to put this code in a code module in VBA (the same place where Macros go)
Look at what I named the sheets: Original and Normalized. You'll either want to change your sheet names or the code
I'm checking for values with a string field of NULL. If the cell is empty, you'll want to check for If IsEmpty(rngCurrent.Value) Then instead.
'
Sub NormalizeSheet()
Dim wsOriginal As Worksheet
Dim wsNormalized As Worksheet
Dim strKey As String
Dim clnHeader As Collection
Dim lngColumnCounter As Long
Dim lngRowCounterOriginal As Long
Dim lngRowCounterNormalized As Long
Dim rngCurrent As Range
Dim varColumn As Variant
Set wsOriginal = ThisWorkbook.Worksheets("Original") 'This is the name of your original worksheet'
Set wsNormalized = ThisWorkbook.Worksheets("Normalized") 'This is the name of the new worksheet'
Set clnHeader = New Collection
wsNormalized.Cells.ClearContents 'This deletes the contents of the destination worksheet'
lngColumnCounter = 2
lngRowCounterOriginal = 1
Set rngCurrent = wsOriginal.Cells(lngRowCounterOriginal, lngColumnCounter)
' We'll loop through just the headers to get a collection of header names'
Do Until IsEmpty(rngCurrent.Value)
clnHeader.Add rngCurrent.Value, CStr(lngColumnCounter)
lngColumnCounter = lngColumnCounter + 1
Set rngCurrent = wsOriginal.Cells(lngRowCounterOriginal, lngColumnCounter)
Loop
'Here we'll reset our Row Counter and loop through the entire data set'
lngRowCounterOriginal = 2
lngRowCounterNormalized = 1
lngColumnCounter = 1
Do While Not IsEmpty(wsOriginal.Cells(lngRowCounterOriginal, lngColumnCounter))
Set rngCurrent = wsOriginal.Cells(lngRowCounterOriginal, lngColumnCounter)
strKey = rngCurrent.Value ' Get the key value from the current cell'
lngColumnCounter = 2
'This next loop parses the denormalized values for each row'
Do While Not IsEmpty(wsOriginal.Cells(lngRowCounterOriginal, lngColumnCounter))
Set rngCurrent = wsOriginal.Cells(lngRowCounterOriginal, lngColumnCounter)
'We're going to check to see if the current value'
'is equal to NULL. If it is, we won't add it to'
'the Normalized Table.'
If rngCurrent.Value = "NULL" Then
'Skip it'
Else
'Add this item to the normalized sheet'
wsNormalized.Range("A" & lngRowCounterNormalized).Value = strKey
wsNormalized.Range("B" & lngRowCounterNormalized).Value = clnHeader(CStr(lngColumnCounter))
wsNormalized.Range("C" & lngRowCounterNormalized).Value = rngCurrent.Value
lngRowCounterNormalized = lngRowCounterNormalized + 1
End If
lngColumnCounter = lngColumnCounter + 1
Loop
lngRowCounterOriginal = lngRowCounterOriginal + 1
lngColumnCounter = 1 'We reset the column counter here because we're on a new row'
Loop
End Sub
I would create a VBA macro that loops through each row and output the data to another page. This would let you create your pivot table in the new page once the data has been outputed.
Not sure how familiar you are with VBA, but this could pretty easily be done by loading the data into an array (or collection of objects if you really want to do it correctly) and writing it back out.
Here is a link to a good VBA document.
http://social.msdn.microsoft.com/Forums/en/isvvba/thread/d712dbdd-c876-4fe2-86d2-7d6323b4262c
Edit
Please note this is not meant to be a fully working solution but really a generic framework to help you in the right direction.
As a generic example that does a lot of what you would need to do (not the best way, but probably the easiest for a beginer), something like this should get you started, although it is hard to say without seeing more of your worksheet.
Sub RowsToColumns ()
Application.ScreenUpdating = False
Dim srcWrkSheet As Worksheet
Dim destWrkSheet As Worksheet
Dim excelData as pExcelData
Dim srcRowNumber As Long
Dim srcRolNumber As Long
Dim destRowNumber As Long
Dim destColNumber As Long
SET srcWrkSheet = Sheets("YourSourceWorkSheetName")
SET destWrkSheet = Sheets("YourDestinationWorkSheetName")
srcRowNumber = 1
srcColNumber = 1
destRowNumber = 1
destColNumber = 1
'Loop until blank row is encountered in column 1
Do
destWrkSheet.Cells(destRowNumber ,1).Value = "Header 1 " & srcWrkSheet.Cells(srcRowNumber,srcColNumber )
destWrkSheet.Cells(destRowNumber ,1).Value = "Header 2 " & srcWrkSheet.Cells(srcRowNumber ,srcColNumber)
srcRowNumber = srcRowNumber + 1
srcColNumber = srcColNumber + 1
destRowNumber = destRowNumber + 1
Loop Until srcWrkSheet .Cells(rowNumber, 1).value = ""
End Sub