I'm currently using excel 2010 and have some data I'm trying to transform so to speak and output the results into sheet 2. I'm not sure where to start and was hoping for some guidance.
The image below is only a sample set of data. The actual spreadsheet consists of 92 rows and 78 columns. The first three columns are name and address and the rest are very similar to what is shown in the image. Some cells have a value, a zero, or blank. The rows in red is what I would like to accomplish.
Here is a solution using VBA.
It assumes that your existing sheet is named "Sheet1", and the new sheet exists and is named "Sheet2".
Option Explicit
Sub CollapseData()
Dim RowNbr As Long
Dim SrcColNbr As Long
Dim DestColNbr As Long
Dim MaxRowNbr As Long
Dim PeriodNbr As Long
Dim MaxPeriodNbr As Long
Dim SrcSheetName As String
Dim DestSheetName As String
Dim SrcSheet As Worksheet
Dim DestSheet As Worksheet
SrcSheetName = "Sheet1"
DestSheetName = "Sheet2"
Set SrcSheet = ThisWorkbook.Worksheets(SrcSheetName)
Set DestSheet = ThisWorkbook.Worksheets(DestSheetName)
' Determine last row number in use
MaxRowNbr = SrcSheet.Cells(Rows.Count, 1).End(xlUp).Row
' Copy name, addr1, and addr2 headings
For DestColNbr = 1 To 3
Call CopyCell(SrcSheet.Cells(1, DestColNbr), DestSheet.Cells(1, DestColNbr))
Next DestColNbr
' Determine number of period columns in use
MaxPeriodNbr = SrcSheet.Cells(1, Columns.Count).End(xlToLeft).Column - 3
' Generate date headings
DestColNbr = 4
For PeriodNbr = 1 To MaxPeriodNbr
DestSheet.Cells(1, DestColNbr) = "date" & Format(PeriodNbr, "##0")
DestSheet.Cells(1, DestColNbr + 1) = "amount" & Format(PeriodNbr, "##0")
DestColNbr = DestColNbr + 2
Next PeriodNbr
' Copy data from Sheet1 to Sheet2
For RowNbr = 2 To MaxRowNbr
' Copy name and address
For DestColNbr = 1 To 3
Call CopyCell(SrcSheet.Cells(RowNbr, DestColNbr), DestSheet.Cells(RowNbr, DestColNbr))
Next DestColNbr
DestColNbr = 4
For SrcColNbr = 4 To MaxPeriodNbr + 3
If SrcSheet.Cells(RowNbr, SrcColNbr) <> 0 Then
' Copy date from Sheet1 to Sheet2
Call CopyCell(SrcSheet.Cells(1, SrcColNbr), DestSheet.Cells(RowNbr, DestColNbr))
' Copy amount from Sheet1 to Sheet2
Call CopyCell(SrcSheet.Cells(RowNbr, SrcColNbr), DestSheet.Cells(RowNbr, DestColNbr + 1))
DestColNbr = DestColNbr + 2
End If
Next SrcColNbr
Next RowNbr
End Sub
Private Sub CopyCell(FromCell As Range, ToCell As Range)
FromCell.Copy
ToCell.PasteSpecial xlPasteValues
ToCell.PasteSpecial xlPasteFormats
End Sub
Here is how you can do it for the example you have shown. It should be simple to replicate the formulas for the whole set of data you have.
To get the first date that has an amount greater than zero, i am doing an array multiplication of the amounts array > 0 and the dates array. then i invert this array (1/array). AGGREGATE function gives you the largest value after ignoring the erros(#div0). Inverting again gives you the first date that has an amount greater than 0.
for the next date, i include one more criteria by checking if the date array has date greater than the date previously calculated, thus giving me the next date.
The formula for amounts are basically HLOOKUPs for the date that was retrieved.
for date 1
=1/AGGREGATE(14,6,1/((D2:I2>0)*D1:I1),1)
for amount 1
=HLOOKUP(D6,$D$1:$I$2,2,FALSE)
for date 2
=1/AGGREGATE(14,6,1/(($D$2:$I$2>0)*($D$1:$I$1>D6)*$D$1:$I$1),1)
for amount 2
=HLOOKUP(F6,$D$1:$I$2,2,FALSE)
for date 3
=1/AGGREGATE(14,6,1/(($D$2:$I$2>0)*($D$1:$I$1>F6)*$D$1:$I$1),1)
for amount 3
=HLOOKUP(H6,$D$1:$I$2,2,FALSE)
Related
I am trying to compare the dates from two different worksheets which have different formats. The first sheet's format is YYYYMMDD, and the second's is DD/MM/YYYY.
A caveat is the second worksheet's year is incorrect (it written as 2020 and should be 2021). The rows may also be in different orders. The first worksheet's data for the date is input as Text and not Date.
As much as I would like to, I can't change the data on these two sheets, and can instead only output to a third sheet (essentially checking the data for entries with the same date, not counting the incorrect year, and outputting something if some key data is different between them).
For example, if one sheet has...
Date
Price
20210101
500
20210102
1000
20210103
2000
...and the other has...
Date
Price
01/01/2020
500
03/01/2020
3000
02/01/2020
750
...I would want to output this to the third sheet...
Date
Sheet 1 Price
Sheet 2 Price
20210102
1000
750
20210103
2000
3000
I have some VBA code which would work in principal, but only if the formats were identical.
' the columns to check in the first worksheet
Const ws1Date As Integer = 1 'first worksheet, Column A
Const ws1Price As Integer = 2 'first worksheet, Column B
' the columns to check in the second worksheet
Const ws2Date As Integer = 1 'second worksheet, Column A
Const ws2Price As Integer = 2 'second worksheet, Column B
' the columns to write to in the result worksheet
Const resultWsDate As Integer = 1 'result worksheet, Column A
Const resultWsPrice As Integer = 2 'result worksheet, Column B
Const resultWsClientPrice As Integer = 3 'result worksheet, Column C
Dim ws1DateArray As Variant, ws2DateArray As Variant
Dim ws1 As Worksheet, ws2 As Worksheet, resultWs As Worksheet
Set ws1 = Sheets(1) 'the first worksheet
Set ws1 = Sheets(2) 'the second worksheet
Set resultWs = Sheets(3) 'the outputted results
Sub compareFiles()
'-- Store ws1 dates in array --
compareRowMaxLength = ws1.Cells(Rows.Count, ws1Date).End(xlUp).Row
ws1DateArray = ws1.Range(Cells(1, ws1Date).Address, _
Cells(compareRowMaxLength, ws1Date).Address).Value
'-- Store ws2 dates in array --
compareRowMaxLength = ws2.Cells(Rows.Count, ws2Date).End(xlUp).Row
ws2DateArray = ws2.Range(Cells(1, ws2Date).Address, _
Cells(compareRowMaxLength, ws2Date).Address).Value
'-- Store ws1 depth in array --
compareRowMaxLength = resultWs.Cells(Rows.Count, ws1Date).End(xlUp).Row
ws1DepthArray = resultWs.Range(Cells(1, ws1Date).Address, _
Cells(compareRowMaxLength, ws1Depth).Address).Value
'-- Interate through arrays --
For compareRow = 2 To UBound(ws2DateArray, 1)
matchData = 0
On Error Resume Next
matchData = WorksheetFunction.Match(ws2DateArray(compareRow, 1), ws1DateArray, 0)
On Error GoTo 0
' if the date of the current row is found in the second sheet
If matchData <> 0 Then
If ws2.Cells(compareRow, ws2Price).Value <> ws1.Cells(matchData, ws1Price).Value Then
' Copy the matching data to the results worksheet
resultWs.Cells(resultRow, resultWsDate).Value = ws1.Cells(matchData, ws1Date).Value
resultWs.Cells(resultRow, resultWsPrice).Value = ws1.Cells(matchData, ws1Price).Value
resultWs.Cells(resultRow, resultWsClientPrice).Value = ws2.Cells(compareRow, ws2Price).Value
End If
End If
Next compareRow
End Sub
I have tried to reformat the date from sheet 2 using something like this within the For loop...
ReplacementYear = 2021
FormatDay = Left(ws2DateArray(compareRow, 1), 2)
FormatMonth = Mid(ws2DateArray(compareRow, 1), 4, 2)
FormattedDate = CStr(ReplacementYear) + CStr(FormatMonth) + CStr(FormatDay)
...and changing matchData = WorksheetFunction.Match(ws2DateArray(compareRow, 1), ws1DateArray, 0) to matchData = WorksheetFunction.Match(FormatDate, ws1DateArray, 0) but it seems Match can't work this way.
Thanks very much for any help!
This may well not be the best solution, but in the off-chance this helps anyone in the future, this is what I came up with.
I can't modify the data in the other worksheets, but I can copy the data into a new worksheet, modify that, and then remove it later on.
' copy the worksheets and modify dates
ws1.Copy After:=Sheets(4)
ws2.Copy After:=Sheets(5)
Set modifyWs1 = Sheets(4)
Set modifyWs2 = Sheets(5)
' fix dates and apply consistent formatting to dates and depth
modifyWs1 .Activate
Dim ws1DateCol As Range
For Each ws1DateCol In Range(Range("A2"), Range("A2").End(xlDown))
ws1DateCol.NumberFormat = "yyyymmdd" ' confirm date format
ws1DateCol.Value = ws1DateCol.Text ' change cells to text so they can be Matched
ws1DateCol.NumberFormat = "#"
Next
' fix dates and apply consistent formatting to dates and depth
modifyWs2.Activate
Dim ws2DateCol As Range
For Each ws2DateCol In Range(Range("A2"), Range("A2").End(xlDown))
ws2DateCol.Value = DateAdd("yyyy", 1, ws2DateCol.Value) ' add 1 to the year, as 2020 should be 2021
ws2DateCol.NumberFormat = "yyyymmdd" ' change date format
ws2DateCol.Value = ws2DateCol.Text ' change cells to text so they can be Matched
ws2DateCol.NumberFormat = "#"
Next
The data from these new columns are then put into the ws1DateArray and ws2DateArray instead, and the WorksheetFunction.Match(ws2DateArray(compareRow, 1), ws1DateArray, 0) works as desired.
I have an Excel table which may contain such:
Screenshot of content from a table, columns C and D
It may be much longer
on top of column D may be an empty cell, but after that it is always the same sequence of contents repeating.
I want to copy and paste in another sheet, with transpose, the contents of the neighboring cells, that is in C, so it would look like:
a screenshot from destination table
It is easy to copy the header, but I am completely unable to have the code loop through and copy all the column C contents that appear left to what is between 1tst and 27tst in the original column D, until all of the blocks of data are copied.
To complicate things even further, I want all empty cells in this destination table to take the value from the cell above, basically filling the blanks that way. This would then look like
Final look of the destination table
In this example, the Words "Algeria | DZ" have to be automatically copied down. The cell under "24tst" remains blank as there is nothing but the header preceding this row.
I have absolutely no starting code here, as these data already made a long process from a Word file through a csv using Ruby, and then the csv is read in and reformatted into various sheets in the Excel file with already long line sof code. That all works so far, but these are my missing steps.
Any help is greatly appreciated. I only started coding again 3 weeks ago, after having never programmed in VBA but years ago in perl and R.
-- In response to VBasic2008 and to try that out I made now a test spreadsheet that looks this way:this is closer to what it really looks like
I changed the constants here:
enter code hereConst sName As String = "Tabelle1" ' Source Worksheet Name
enter code hereConst sFirst As String = "C2" ' Source First Cell Address
enter code hereConst tName As String = "Tabelle2" ' Target Worksheet Name
enter code hereConst tFirst As String = "B1" ' Target First Cell Address
The groups will actually be constant in length, actually more than 11, but that can be fixed later.
These:
1tst
2tst
3tst
11tst
4tst
22tst
23tst
24tst
25tst
26tst
27tst -
I pasted this already into target sheet.
What I get from my test using my thus modified solution from VBasic2008 is this:
Afghanistan | AF Ă…land Islands | AX Albania | AL Algeria | DZ American Samoa | AS Belgium | BE Belize | BZ 24tst Bermuda | BM Bhutan | BT Bolivia | BO
Bonaire, Sint Eustatius and Saba | BQ Bosnia and Herzegovina | BA Botswana | BW Algeria | DZ Brazil | BR Christmas Island | CX Cocos (Keeling) Islands | CC Colombia | CO Comoros | KM n/a Congo | CD
This is almost perfect, except for it should not, in the first row in the target sheet after the headers, copied down the "24tst". Can this still be tweaked?
A Copy Transpose
This will work correctly only if the data is consistent i.e. 11 rows of data and 1 empty (Next-Group) row (can be changed in the constants section) i.e. if you have 5 data sets, there has to be 60 rows of data. If there is 65, only 60 will be processed and if there is 59, only 48 will be processed.
The following image shows what the current setup in the code will produce (without the formatting).
The Code
Option Explicit
Sub transposeData()
Const sName As String = "Sheet1" ' Source Worksheet Name
Const sFirst As String = "A2" ' Source First Cell Address
Const tName As String = "Sheet1" ' Target Worksheet Name
Const tFirst As String = "D1" ' Target First Cell Address
Const NoE As Long = 11 ' Number of Elements
Const NoER As Long = 1 ' Number of Empty Rows
Dim wb As Workbook
Set wb = ThisWorkbook ' The workbook containing this code.
' Define Source Worksheet ('ws').
Dim ws As Worksheet
Set ws = wb.Worksheets(sName)
' Define Source First Cell ('First').
Dim First As Range
Set First = ws.Range(sFirst)
' Define Source Last Cell ('Last').
Dim Last As Range
Set Last = First.Offset(ws.Rows.Count - First.Row, 1).End(xlUp)
If Last.Row - First.Row + 1 < NoE Then
GoTo ProcExit
End If
' Define Source Range ('rng').
Dim rng As Range
Set rng = ws.Range(First, Last)
' Write values from Source Range to Source Array ('Source').
Dim Source As Variant
Source = rng.Value
' Define number of Data Sets ('NoDS').
Dim NoDS As Long
NoDS = Int(UBound(Source, 1) / (NoE + NoER))
' Define Target Number of Rows ('NoR').
Dim NoR As Long
NoR = NoDS + 1
' Define Target Array ('Target').
Dim Target As Variant
ReDim Target(1 To NoR, 1 To NoE)
' Declare additional variables for the upcoming loops.
Dim CurrentValue As Variant ' Source Current Value
Dim CurrentLR As Long ' Source Current Last Row
Dim j As Long ' Target Columns Counter
Dim i As Long ' Target Rows Counter
' Write headers.
For j = 1 To NoE
Target(1, j) = Source(j, 2)
Next j
' Write data.
For i = 2 To NoR
CurrentLR = (i - 2) * (NoE + NoER)
For j = 1 To NoE
CurrentValue = Source(CurrentLR + j, 1)
If Not IsEmpty(CurrentValue) Then
Target(i, j) = CurrentValue
Else
Target(i, j) = Target(i - 1, j)
End If
Next j
Next i
' Define Target Worksheet ('ws').
Set ws = wb.Worksheets(tName)
' Define Target First Cell ('First').
Set First = ws.Range(tFirst)
' Define Target Range ('rng').
Set rng = First.Resize(NoR, NoE)
' Write values from Target Array to Target Range.
rng.Value = Target
' Inform user
MsgBox "Data transferred.", vbInformation, "Success"
ProcExit:
End Sub
EDIT
Tiny Change
Instead of Target(i, j) = Target(i - 1, j) use
If i > 2 Then
Target(i, j) = Target(i - 1, j)
End If
I think the easiest way of doing this is looping through cells with headers and checking each value.
When you find your "next-group" cell then trigger some ifs;
Example program which covers your problem below:
Sub solution()
'Set first row
Dim firstrow As Integer
firstrow = 1
'Find last row
Dim lastrow As Integer
lastrow = Cells(Rows.Count, 1).End(xlUp).Row 'Go to bottom of file and jump up to last non-empty cell
'Set first column
Dim firstcolumn As Integer
firstcolumn = 1
'find last column
Dim lastcolumn As Integer
lastcolumn = 2
'Set first cell of target table
Dim targetrange As Range
Set targetrange = Range("E2")
Dim i As Integer
Dim cnt As Integer 'conuter for creating offset (for columns)
Dim cnt2 As Integer 'conuter for creating offset (for rows)
'Copy headers
cnt = 0
For i = firstrow To lastrow
If Cells(i, lastcolumn).Value = "next-group" Then Exit For
Cells(i, lastcolumn).Copy targetrange.Offset(0, cnt)
cnt = cnt + 1
Next i
'Copy data
cnt = 0
cnt2 = 1
For i = firstrow To lastrow
'If we have text "next group"
If Cells(i, lastcolumn).Value = "next-group" Then
cnt = 0 'start with first column
cnt2 = cnt2 + 1 'Start with next row
'This cell is not copied
Else
'cell is copied
Cells(i, firstcolumn).Copy targetrange.Offset(cnt2, cnt)
'column counter is increased
cnt = cnt + 1
End If
Next i
'Change blank cells in current region into formula which points to cell one row above
'targetrange.CurrentRegion.SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "=R[-1]C"
'Same formula but keep cells in first row of data blank istead copying header
Dim targetArea As Range
Set targetArea = targetrange.CurrentRegion
targetArea.Offset(2).Resize(targetArea.Rows.Count - 2).SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "=R[-1]C"
End Sub
I didn't cover case when you have empty cell in first row as you didn't described what you're expecting (at this moment it have same formula so it will be filled with header value).
UPDATE: I didnt put "=" inside R1C1 formula, now its fixed.
UPDATE2: Changed part of filling empty cells so it skips first 2 rows (Headers and first row of data) instead filling it as mentioned in question update
I have some excel data which are now in rows and I want to get them into columns in an easy an effective way and I am not able to figure out how to do it. Any advice will be welcome! Thanks.
Example: turn sth like this in Excel
Team A
John
Team B
Peter
John
Team C
John
Peter
Oliver
Anna
Team D
Anna
into:
Team A John
Team B Peter John
Team C John Peter Oliver Anna
Team D Anna
I'm guessing your real data is much longer than this list so here is what i would do in that case.
First, put the list in column B and add a formula that copies the Team down column A:
*note you have to copy and paste the value from b2 into a2 and start the formula on a3.
Type the formula =IF(LEFT(B3,4)="Team",B3,A2) in cell a3 and drag it down (or control shift down then control d to fill down). What is this formula doing? It looks at the B cell, if it starts with "Team" it uses the value of that cell, otherwise it uses the value of the cell above (which will be another "Team").
Then, copy and paste and values column A so you don't loose the formula results after the next steps:
Filter column B "player" on the search term "team" and delete those entire rows:
Now you have column A of teams, Column B of players and use this formula in column C: =IF(A2=A1,CONCATENATE(C1," ",B2),CONCATENATE(A2," ",B2)).
This formula looks at the Team column and if it differs, it start a new chain of team and player otherwise it adds the player to the chain above of team and player.
I hope you can follow the logic here and accomplish what you are trying to do. Let me know how it goes.
Column to Vertical List
Option Explicit
'*******************************************************************************
' Purpose: Processes a one-column range containing groups of title-values data,
' transposing the titles to the first column of a range and the values
' to columns next to the title thus creating a vertical list.
'*******************************************************************************
Sub ColumnToVerticalList()
Const cStrSheet As String = "Sheet1" ' Worksheet Name
Const cLngFirstRow As Long = 2 ' First Row of Source Data
Const cStrColumn As String = "A" ' Column of Source Data
Const cStrSearch As String = "Team" ' Search String
Const cStrCell As String = "C2" ' Target Cell
Dim arrSource As Variant ' Source Array
Dim lngArr As Long ' Source Array Row Counter
Dim arrTarget As Variant ' Target Array
Dim lngRows As Long ' Number of Rows (Counter) in Target Array
Dim iCols As Integer ' Number of Columns (Counter) in Target Array
Dim iColsTemp As Integer ' Target Array Columns Counter
Dim strTargetRange As String ' Target Range
' Paste the calculated source range into the source array - arrSource.
With ThisWorkbook.Worksheets(cStrSheet)
arrSource = .Range( _
.Cells(cLngFirstRow, cStrColumn), _
.Cells(.Cells(Rows.Count, cStrColumn).End(xlUp).Row, cStrColumn))
End With
' Calculate the number of rows and columns of the target array - arrTarget.
iColsTemp = 1
For lngArr = LBound(arrSource) To UBound(arrSource)
If InStr(1, arrSource(lngArr, 1), cStrSearch, vbTextCompare) <> 0 Then
If iColsTemp > iCols Then
iCols = iColsTemp
End If
iColsTemp = 1
Debug.Print arrSource(lngArr, 1)
lngRows = lngRows + 1
Else
iColsTemp = iColsTemp + 1
End If
Next
' Calculate the target range address.
strTargetRange = Range(Cells(Range(cStrCell).Row, Range(cStrCell).Column), _
Cells(Range(cStrCell).Row + lngRows - 1, _
Range(cStrCell).Column + iCols - 1)).Address
' Resize the target array.
ReDim arrTarget(1 To lngRows, 1 To iCols)
' Write data from source array to target array.
lngRows = 0
iCols = 1
For lngArr = LBound(arrSource) To UBound(arrSource)
If InStr(1, arrSource(lngArr, 1), cStrSearch, vbTextCompare) <> 0 Then
iCols = 1
lngRows = lngRows + 1
arrTarget(lngRows, 1) = arrSource(lngArr, 1)
Else
iCols = iCols + 1
arrTarget(lngRows, iCols) = arrSource(lngArr, 1)
End If
Next
' Paste data of the target array into the target range
ThisWorkbook.Worksheets(cStrSheet).Range(strTargetRange) = arrTarget
End Sub
Excel 2010. I am trying to write a macro that could copy a set of data multiple times based on criteria on another sheet, but I've been stuck for a long time. I very much appreciate any help that could be offered to help me solve this problem.
Step 1: In the "Criteria" worksheet, there are three columns in which each row contains a specific combination of data. The first set of combination is "USD, Car".
Criteria worksheet
Step 2: Then the macro will move to the Output worksheet (please refer to the below link for screenshots), and then filter column A and B with the first set of criteria "USD" and "Car" in the "Criteria" worksheet.
Step 3: Afterwards, the macro will copy the filtered data into the last blank row. But the tricky part here is that, the filtered data has to be copied two times (as the "Number of set" column in the "Criteria" tab is 3 in this combination, and it doesn't have to copy the data three times since the filtered data would be treated as the first set of data)
Step4: After the filtered data have been copied, the "Set" column D will need to fill in the corresponding number of set that the rows are in. Therefore, in this 1st example, cell D2 and D8 will have "1" value, cell D14-15 will have "2" value, and cell D16-17 will have "3" value.
Step5: The macro will then move back to the "Criteria" worksheet and continue to based on the 2nd set of combination "USD, Plane" to filter the data in the "Output" worksheet. Again, it will copy the filtered data based on the "Number of set" in the "Criteria" worksheet. This process will continue until all the different combinations in the "Criteria" worksheet have been processed.
Output worksheet
Ok sorry for delay, here is a working version
you just have to add a sheet called "BF" because the autofilter count wasn't working properly so I had to use another sheet
Sub testfct()
Dim ShC As Worksheet
Set ShC = ThisWorkbook.Sheets("Criteria")
Dim EndRow As Integer
EndRow = ShC.Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To EndRow
Get_Filtered ShC.Cells(i, 1), ShC.Cells(i, 2), ShC.Cells(i, 3)
Next i
End Sub
Sub Get_Filtered(ByVal FilterF1 As String, ByVal FilterF2 As String, ByVal NumberSetsDisered As Integer)
Dim NbSet As Integer
NbSet = 0
Dim ShF As Worksheet
Set ShF = ThisWorkbook.Sheets("Output")
Dim ColCr1 As Integer
Dim ColCr2 As Integer
Dim ColRef As Integer
ColCr1 = 1
ColCr2 = 2
ColRef = 4
If ShF.AutoFilterMode = True Then ShF.AutoFilterMode = False
Dim RgTotal As String
RgTotal = "$A$1:$" & ColLet(ShF.Cells(1, Columns.Count).End(xlToLeft).Column) & "$" & ShF.Cells(Rows.Count, 1).End(xlUp).Row
ShF.Range(RgTotal).AutoFilter field:=ColCr1, Criteria1:=FilterF1
ShF.Range(RgTotal).AutoFilter field:=ColCr2, Criteria1:=FilterF2
'Erase Header value, fix? or correct at the end?
ShF.AutoFilter.Range.Columns(ColRef).Value = 1
Sheets("BF").Cells.ClearContents
ShF.AutoFilter.Range.Copy Destination:=Sheets("BF").Cells(1, 1)
Dim RgFilt As String
RgFilt = "$A$2:$B" & Sheets("BF").Cells(Rows.Count, 1).End(xlUp).Row '+ 1
Dim VR As Integer
'Here was the main issue, the value I got with autofilter was not correct and I couldn't figure out why....
'ShF.AutoFilter.Range.SpecialCells(xlCellTypeVisible).Rows.Count
'Changed it to a buffer sheet to have correct value
VR = Sheets("BF").Cells(Rows.Count, 1).End(xlUp).Row - 1
Dim RgDest As String
ShF.AutoFilterMode = False
'Now we need to define Set's number and paste N times
For k = 1 To NumberSetsDisered - 1
'define number set
For j = 1 To VR
ShF.Cells(Rows.Count, 1).End(xlUp).Offset(j, 3) = k + 1
Next j
RgDest = "$A$" & ShF.Cells(Rows.Count, 1).End(xlUp).Row + 1 & ":$B$" & (ShF.Cells(Rows.Count, 1).End(xlUp).Row + VR)
Sheets("BF").Range(RgFilt).Copy Destination:=ShF.Range(RgDest)
Next k
ShF.Cells(1, 4) = "Set"
Sheets("BF").Cells.ClearContents
'ShF.AutoFilterMode = False
End Sub
And the function to get column letter using an integer input :
Function ColLet(x As Integer) As String
With ActiveSheet.Columns(x)
ColLet = Left(.Address(False, False), InStr(.Address(False, False), ":") - 1)
End With
End Function
I'm attempting to automate Excel in a way that will save me countless hours of tedious data entry. Here's my problem.
We need to print barcodes for all of our inventory, which includes 4,000 variants each with a specific quantity.
Shopify is our e-commerce platform and they do not support customized exports; however, can export a CSV of all variants, which includes an inventory count column.
We use Dymo for our barcode printing hardware/software. Dymo will only print one label per row (it ignores the quantity column).
Is there a way to automate excel to duplicate the row "x" number of times based on the value in the inventory column?
Here's a sample of the data:
https://www.evernote.com/shard/s187/sh/b0d5b92a-c5f6-469c-92fb-3d4e03d97544/d176d3448ba0cafbf3d61506402d9e8b/res/254447d2-486d-454f-8871-a0962f03253d/skitch.png
If Column N = 0, ignore and move to next row
If Column N > 1, copy current row, "N" number of times (to a separate sheet)
I tried to find someone who had done something similar so that I could modify the code, but after an hour of searching I'm still right where I started. Thank you in advance for the help!
David beat me to it but an alternate approach never hurt anyone.
Consider the following data
Item Cost Code Quantity
Fiddlesticks 0.8 22251554787 0
Woozles 1.96 54645641 3
Jarbles 200 158484 4
Yerzegerztits 56.7 494681818 1
With this function
Public Sub CopyData()
' This routing will copy rows based on the quantity to a new sheet.
Dim rngSinglecell As Range
Dim rngQuantityCells As Range
Dim intCount As Integer
' Set this for the range where the Quantity column exists. This works only if there are no empty cells
Set rngQuantityCells = Range("D1", Range("D1").End(xlDown))
For Each rngSinglecell In rngQuantityCells
' Check if this cell actually contains a number
If IsNumeric(rngSinglecell.Value) Then
' Check if the number is greater than 0
If rngSinglecell.Value > 0 Then
' Copy this row as many times as .value
For intCount = 1 To rngSinglecell.Value
' Copy the row into the next emtpy row in sheet2
Range(rngSinglecell.Address).EntireRow.Copy Destination:= Sheets("Sheet2").Range("A" & Rows.Count).End(xlUp).Offset(1)
' The above line finds the next empty row.
Next
End If
End If
Next
End Sub
Produces the following output on sheet2
Item Cost Code Quantity
Woozles 1.96 54645641 3
Woozles 1.96 54645641 3
Woozles 1.96 54645641 3
Jarbles 200 158484 4
Jarbles 200 158484 4
Jarbles 200 158484 4
Jarbles 200 158484 4
Yerzegerztits 56.7 494681818 1
The caveats with this code is that there can be no empty fields in the Quantity column. I used D so feel free to substitute N for your case.
Should be enough to get you started:
Sub CopyRowsFromColumnN()
Dim rng As Range
Dim r As Range
Dim numberOfCopies As Integer
Dim n As Integer
'## Define a range to represent ALL the data
Set rng = Range("A1", Range("N1").End(xlDown))
'## Iterate each row in that data range
For Each r In rng.Rows
'## Get the number of copies specified in column 14 ("N")
numberOfCopies = r.Cells(1, 14).Value
'## If that number > 1 then make copies on a new sheet
If numberOfCopies > 1 Then
'## Add a new sheet
With Sheets.Add
'## copy the row and paste repeatedly in this loop
For n = 1 To numberOfCopies
r.Copy .Range("A" & n)
Next
End With
End If
Next
End Sub
Might be a bit late to answer, however this could help others.
I have tested this solution on Excel 2010.
Say: "Sheet1" is the name of the sheet where your data is located
and "Sheet2" is the sheet where you want your repeated data.
Assuming you have these sheets created, try the below code.
Sub multiplyRowsByCellValue()
Dim rangeInventory As Range
Dim rangeSingleCell As Range
Dim numberOfRepeats As Integer
Dim n As Integer
Dim lastRow As Long
'Set rangeInventory to all of the Inventory Data
Set rangeInventory = Sheets("Sheet1").Range("A2", Sheets("Sheet1").Range("D2").End(xlDown))
'Iterate each row of the Inventory Data
For Each rangeSingleCell In rangeInventory.Rows
'number of times to be repeated copied from Sheet1 column 4 ("C")
numberOfRepeats = rangeSingleCell.Cells(1, 3).Value
'check if numberOfRepeats is greater than 0
If numberOfRepeats > 0 Then
With Sheets("Sheet2")
'copy each invetory item in Sheet1 and paste "numberOfRepeat" times in Sheet2
For n = 1 To numberOfRepeats
lastRow = Sheets("Sheet1").Range("A1048576").End(xlUp).Row
r.Copy
Sheets("Sheet1").Range("A" & lastRow + 1).PasteSpecial xlPasteValues
Next
End With
End If
Next
End Sub
This solution is slightly modified version of David Zemens solution.