I've been trying to tinker with this source code that transposes 1 column separated by spaces.
Sub Transpose()
Dim lastrow As Long, i As Long, j As Long, iStart As Long, iEnd As Long
Dim ws As Worksheet
Application.ScreenUpdating = False
With Sheets("Sheet1")
Set ws = Sheets.Add(after:=Sheets(Sheets.Count))
lastrow = .Cells(Rows.Count, "A").End(xlUp).row
iStart = 1
For i = 1 To lastrow + 1
If .Range("A" & i).Value = "" Then
iEnd = i
j = j + 1
.Range(.Cells(iStart, 1), .Cells(iEnd, 1)).Copy
ws.Range("A" & j).PasteSpecial Paste:=xlPasteValues, Transpose:=True
iStart = iEnd + 1
End If
Next i
End With
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
I'm trying to take take 4 columns ranges with variable rows
[
And transpose each range adjacently so that it looks like this:
Any input appreciated.
Try this out:
Sub Transpose()
Dim ws As Worksheet, cCopy As Range, cPaste As Range
Set ws = Sheets("Sheet1")
Set cCopy = ws.Range("A1") 'top-left of first data block
Set cPaste = ws.Range("F1") 'first output cell
Do While Len(cCopy.Value) > 0 'while have data to transpose
With cCopy.CurrentRegion
Debug.Print "Copying", .Address, " to ", cPaste.Address
cPaste.Resize(.Columns.Count, .Rows.Count) = _
Application.Transpose(.Value)
Set cPaste = cPaste.Offset(.Columns.Count + 1) 'next paste position
Set cCopy = cCopy.Offset(.Rows.Count + 1) 'next data block
End With
Loop
End Sub
Took way too long to do this and the most atrocious architecture but it works.
r = 1
c = 1
cl = 6
rw = 1
For r = 1 To 13
For c = 1 To 4
If Cells(r, c) <> "" Then
Cells(rw, cl) = Cells(r, c)
rw = rw + 1
End If
Next
'If Cells(r, c) = "" Then cl = 6
rw = 1
cl = cl + 1
Next
rw = 5
cl = 6
For r = 1 To 4
For c = 10 To 12
Cells(rw, cl) = Cells(r, c)
cl = cl + 1
Next
rw = rw + 1
cl = 6
Next
rw = 9
cl = 6
For r = 1 To 4
For c = 14 To 18
Cells(rw, cl) = Cells(r, c)
cl = cl + 1
Next
rw = rw + 1
cl = 6
Next
Range("J1:R4").ClearContents
Try this code:
Sub SubRollData()
'Declarations.
Dim RngSource As Range
Dim RngTarget As Range
Dim DblRowOffset As Double
Dim DblColumnOffset As Double
'Settings.
Set RngSource = Range("A1")
Set RngTarget = Range("F1")
'Checkpoint for the block processing.
CP_Block:
'Covering each column.
For DblColumnOffset = 0 To 3
'Setting DblRowOffset to start covering for the first row of the block.
DblRowOffset = 0
'Covering each row of the block of the given column until an empty cell is fount.
Do Until RngSource.Offset(DblRowOffset, DblColumnOffset) = ""
'Reporting the data with switched offset.
RngTarget.Offset(DblColumnOffset, DblRowOffset).Value = RngSource.Offset(DblRowOffset, DblColumnOffset).Value
'Setting DblRowOffset for the next row.
DblRowOffset = DblRowOffset + 1
Loop
Next
'Setting RngSource to aim at the next block.
If RngSource.Offset(1, 0) = "" Then
Set RngSource = RngSource.Offset(2, 0)
Else
Set RngSource = RngSource.End(xlDown).Offset(2, 0)
End If
'Setting RngSource to aim at the next empty row to fill in with data.
If RngTarget.Offset(1, 0) = "" Then
Set RngTarget = RngTarget.Offset(1, 0)
Else
Set RngTarget = RngTarget.End(xlDown).Offset(1, 0)
End If
'If RngSource has no data, there is no more block to be processed. Otherwise, the next block is processed.
If RngSource.Value <> "" Then GoTo CP_Block
End Sub
It works with the example you've given and also with isoletd (single row) source data.
Just for fun, here is a possible formula based solution to be placed in cell F1 and dragged:
=IF(COLUMN(F1)-COLUMN($F1)+1>=AGGREGATE(15,6,1/($A:$A="")*ROW($A:$A),QUOTIENT(ROW(F1)-ROW(F$1),4)+1)-IF(QUOTIENT(ROW(F1)-ROW(F$1),4)=0,0,AGGREGATE(15,6,1/($A:$A="")*ROW($A:$A),QUOTIENT(ROW(F1)-ROW(F$1),4))),"",INDEX($A:$D,COLUMN(F1)-COLUMN($F1)+1+IF(QUOTIENT(ROW(F1)-ROW(F$1),4)=0,0,AGGREGATE(15,6,1/($A:$A="")*ROW($A:$A),QUOTIENT(ROW(F1)-ROW(F$1),4))),MOD(ROW(F1)-ROW(F$1),4)+1))
Naturally it's really heavy and stupidly complicated, but as i said: made it just for fun.
Transpose Groups of Data to a New Worksheet
Sub TransposeGroups()
' Source - use as-is (read (copy) from)
Const sName As String = "Sheet1"
Const sFirstRowAddress As String = "A1:D1"
Const sMandatoryColumnIndex As Long = 1 ' dictates if empty row (gap)
' Destination - delete if exists and put last (write (paste) to)
Const dName As String = "Result"
Const dFirstCellAddress As String = "A1"
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Write the values from the source range to a 2D one-based array
' and write its upper limits to variables.
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim sData As Variant
Dim srCount As Long
Dim scCount As Long
With sws.Range(sFirstRowAddress)
Dim lCell As Range
With .Columns(sMandatoryColumnIndex)
Set lCell = .Resize(sws.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
End With
If lCell Is Nothing Then
MsgBox "No data in column " & sMandatoryColumnIndex & ".", _
vbCritical
Exit Sub
End If
scCount = .Columns.Count
srCount = lCell.Row - .Row + 1
sData = .Resize(srCount).Value
End With
' Loop through the rows of the source array and map the first row,
' the last row and the following gap count (empty rows) in each row
' of three columns of another 2D one-based array.
' Note that this array has the same number of rows as the source array,
' but the data of interest will be in much fewer rows ('mr').
' (Probably a collection of collections (or three element arrays)
' would have been a better choice.)
Dim mArr() As Long: ReDim mArr(1 To srCount, 1 To 3)
Dim sr As Long
Dim sValueFound As Boolean
Dim mr As Long
Dim ccCount As Long
Dim dcCount As Long
Dim GapCount As Long
For sr = 1 To srCount
If Len(CStr(sData(sr, sMandatoryColumnIndex))) > 0 Then
If Not sValueFound Then
mr = mr + 1
mArr(mr, 1) = sr ' first row
sValueFound = True
End If
Else
If sValueFound Then
sValueFound = False
mArr(mr, 2) = sr - 1 ' last row
ccCount = sr - mArr(mr, 1)
If ccCount > dcCount Then dcCount = ccCount
End If
mArr(mr, 3) = mArr(mr, 3) + 1 ' gap
GapCount = GapCount + 1 ' to determine the number of rows of 'dData'
End If
Next sr
' The very last row (of interest).
mArr(mr, 2) = srCount
ccCount = sr - mArr(mr, 1)
If ccCount > dcCount Then dcCount = ccCount
' Using the source array and the information from the mapping array,
' write the results to the destination array.
Dim drCount As Long: drCount = mr * scCount + GapCount
Dim dData As Variant: ReDim dData(1 To drCount, 1 To dcCount)
Dim drFirst As Long
Dim sc As Long
Dim dc As Long
For mr = 1 To mr
For sc = 1 To scCount
For sr = mArr(mr, 1) To mArr(mr, 2)
dc = dc + 1
dData(drFirst + sc, dc) = sData(sr, sc)
Next sr
dc = 0
Next sc
drFirst = drFirst + sc + mArr(mr, 3) - 1
Next mr
' Write the values from the destination array to a new worksheet.
' Check if a sheet with the same name exists.
Dim dsh As Object
On Error Resume Next
Set dsh = wb.Sheets(dName)
On Error GoTo 0
' If it exists, delete it without confirmation.
If Not dsh Is Nothing Then
Application.DisplayAlerts = False
dsh.Delete
Application.DisplayAlerts = True
End If
' Add a new worksheet and rename it accordingly.
Dim dws As Worksheet
Set dws = wb.Worksheets.Add(After:=wb.Sheets(wb.Sheets.Count))
dws.Name = dName
' Write the values from the destination array to the destination worksheet.
With dws.Range(dFirstCellAddress)
.Resize(drCount, dcCount).Value = dData
End With
' Inform.
MsgBox "Groups transposed.", vbInformation
End Sub
Related
I have 2 sheets with multiple rows and columns like this:
Sheet1:
I want to search each value from Sheet1, Column B in Sheet2, Column B then:
If the value is equal => Copy the rest of the row in sheet1.
At the end, sheet1 should look like this:
and Sheet2 the same, I don't modify in that, only I take from that the rest of the rows.
Thank you very much,
I have tried something like this:
Sub Compare()
Dim n As Integer
Dim sh As Worksheets
Dim r As Range
n = 1000
Dim match As Boolean
Dim valE As Double
Dim valI As Double
Dim I As Long, J As Long
For I = 2 To n
val1 = Worksheets("Sheet1").Range("B" & I).Value
val2 = Worksheets("Sheet2").Range("B" & I).Value
If val1 = val2 Then
Worksheets("Sheet1").Range("C" & I).Value = Worksheets("Sheet2").Range("C" & I)
Worksheets("Sheet1").Range("D" & I).Value = Worksheets("Sheet2").Range("D" & I)
Worksheets("Sheet1").Range("E" & I).Value = Worksheets("Sheet2").Range("E" & I)
I = I + 1
End If
Next I
Application.ScreenUpdating = True
End Sub
It works for 10 values or so, but I have 1200 values and it just doesn't do anything.
A VBA Lookup: Copy Rows
Type Wks
Name As String
LookupColumn As Long
FirstColumn As Long
End Type
Sub LookupData()
Dim Src As Wks
Src.Name = "Sheet2"
Src.LookupColumn = 2
Src.FirstColumn = 3
Dim Dst As Wks
Dst.Name = "Sheet1"
Dst.LookupColumn = 2
Dst.FirstColumn = 3
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Read source.
Dim sws As Worksheet: Set sws = wb.Worksheets(Src.Name)
Dim srg As Range, slData() As Variant, srCount As Long, cCount As Long
With sws.Range("A1").CurrentRegion
srCount = .Rows.Count - 1
cCount = .Columns.Count
If srCount = 0 Then Exit Sub
Set srg = .Resize(srCount).Offset(1)
End With
With srg.Columns(Src.LookupColumn)
If srCount = 1 Then
ReDim slData(1 To 1, 1 To 1): slData(1, 1) = .Value
Else
slData = .Value
End If
End With
Dim cOffset As Long: cOffset = Src.FirstColumn - 1
cCount = cCount - cOffset
Dim svData() As Variant
With srg.Resize(, cCount).Offset(, cOffset)
If srCount * cCount = 1 Then
ReDim svData(1 To 1, 1 To 1): svData = .Value
Else
svData = .Value
End If
End With
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Dim r As Long, cString As String
For r = 1 To srCount
cString = CStr(slData(r, 1))
If Not dict.Exists(cString) Then dict(cString) = r
Next r
' Read destination.
Dim dws As Worksheet: Set dws = wb.Worksheets(Dst.Name)
Dim drg As Range, dlData() As Variant, drCount As Long
With dws.Range("A1").CurrentRegion
drCount = .Rows.Count - 1
If drCount = 0 Then Exit Sub
Set drg = .Resize(drCount).Offset(1)
End With
With drg.Columns(Dst.LookupColumn)
If drCount = 1 Then
ReDim dlData(1 To 1, 1 To 1): dlData(1, 1) = .Value
Else
dlData = .Value
End If
End With
Dim dvData() As Variant: ReDim dvData(1 To drCount, 1 To cCount)
' Lookup and write to destination.
Dim dr As Long, c As Long
For r = 1 To drCount
cString = CStr(dlData(r, 1))
If dict.Exists(cString) Then
dr = dict(cString)
For c = 1 To cCount
dvData(r, c) = svData(dr, c)
Next c
End If
Next r
Dim dfCell As Range: Set dfCell = drg.Columns(Dst.FirstColumn).Cells(1)
Dim dvrg As Range: Set dvrg = dfCell.Resize(drCount, cCount)
dvrg.Value = dvData
' Inform.
MsgBox "Data copied.", vbInformation
End Sub
I have two macros that I would like to combine but somehow its not going well...
I want a macro that will get only unique values from a range and input them into another sheet every second row starting from row no 3
Could anyone tell me how should I combine those two macros?
I have tried to change .Font.Size = 20 with Application.Transpose(objDict.keys) but it didn't work.
Sub UniqueValue()
Dim X
Dim objDict As Object
Dim lngRow As Long
Set objDict = CreateObject("Scripting.Dictionary")
X = Application.Transpose(Range([a1], Cells(Rows.Count, "A").End(xlUp)))
For lngRow = 1 To UBound(X, 1)
objDict(X(lngRow)) = 1
Next
Range("F1:F" & objDict.Count) = Application.Transpose(objDict.keys)
End Sub
Sub EverySecond()
Dim EndRow As Long
EndRow = Range("A" & Rows.Count).End(xlUp).Row
For ColNum = 5 To EndRow Step 2
Range(Cells(ColNum, 2), Cells(ColNum, 2)).Font.Size = 20
Next ColNum
End Sub
Copy Unique Values to Every Other Row
Option Explicit
Sub UniqueEveryOther()
Const sName As String = "Sheet1"
Const sFirstCellAddress As String = "A2"
Const dName As String = "Sheet2"
Const dFirstCellAddress As String = "A2"
Dim wb As Workbook: Set wb = ThisWorkbook
' Reference the source range.
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim srg As Range
Dim srCount As Long
With sws.Range(sFirstCellAddress)
Dim lCell As Range: Set lCell = .Resize(sws.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If lCell Is Nothing Then Exit Sub
srCount = lCell.Row - .Row + 1
Set srg = .Resize(srCount)
End With
' Write the values from the source range to an array.
1
Dim Data As Variant
If srCount = 1 Then ' one cell
ReDim Data(1 To 1, 1 To 1): Data(1, 1) = srg.Value
Else ' multiple cells
Data = srg.Value
End If
' Write the unqiue values from the array to a dictionary.
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Dim Key As Variant
Dim r As Long
For r = 1 To srCount
Key = Data(r, 1)
If Not IsError(Key) Then
If Len(Key) > 0 Then
dict(Key) = Empty
End If
End If
Next r
If dict.Count = 0 Then Exit Sub
' Write the unqiue values from the dictionary to the array.
ReDim Data(1 To 2 * dict.Count - 1, 1 To 1)
r = -1
For Each Key In dict.Keys
r = r + 2
Data(r, 1) = Key
Next Key
' Write the unique values from the array to the destination range.
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
With dws.Range(dFirstCellAddress)
.Resize(r).Value = Data
.Resize(dws.Rows.Count - .Row - r + 1).Offset(r).Clear
'.EntireColumn = AutoFit
End With
'wb.Save
MsgBox "Uniques populated.", vbInformation
End Sub
I have an Excel sheet with 4 pages that takes input budgetary adjustment data and reformats into two different formats for entry into different budget softwares.
On the sheets first page, the upload page (feed data), data is given in rows of budget adjustments. These adjustments always come in even numbers of rows because for every account that has money adjusted out of it, another account has that money adjusted into it. In each row there are a number of non-unique qualitative columns that describe the adjustment and then 12 month columns that record the monetary aspects of the adjustment. Some rows have only one month of the 12 filled and can be left alone. Other adjustments occur over several months and thus have several of the months columns filled.
For input into the two budget softwares, these rows that have multiple month columns filled with data need to be expanded into multiple new rows with only one of the 12 columns filled. For clarity, here's what the transformation should look like:
Input:
Output:
How can you do this with input data where some rows don't need to be transformed, some include 2 months of transactions, and some could include up to 12?
Option Explicit
Sub Only_one_data_value_per_row()
Dim myR As Range
Dim rowCt As Integer
Dim actRange As Range
Dim dataCt As Integer
Dim iCt As Integer
Dim myCell As Range
Set actRange = Range("A1").CurrentRegion
For rowCt = actRange.Rows.Count To 2 Step -1
With ActiveSheet.Rows(rowCt)
dataCt = Application.WorksheetFunction.Count(.Range("E1:P1"))
'Debug.Print .Range("E1:P1").Address, dataCt)
For iCt = 1 To dataCt - 1
Rows(rowCt + 1).EntireRow.Insert
Rows(rowCt).Range("A1:D1").Copy Rows(rowCt + 1).Range("A1")
Next iCt
iCt = 0
For Each myCell In Rows(rowCt).Range("E1:P1")
'Debug.Print rowCt; ":"; (nonEmptyCell)
If myCell.Value <> "" Then
Debug.Print myCell.Value
If Val(myCell.Value) = 0 Then
MsgBox "The value of the cell " & myCell.Address & _
" is 0! The cell will be deleted!"
myCell.Value = ""
Else
If iCt > 0 Then
myCell.Offset(iCt, 0).Value = myCell.Value
myCell.Value = ""
End If
iCt = iCt + 1
End If
End If
Next myCell
End With
Next rowCt
End Sub
Input:
Output:
Transform Data: One Value Per Row
Adjust the values in the constants section.
Option Explicit
Sub TransformOneValuePerRow()
' Source
Const sName As String = "Sheet1"
Const sFirstCellAddress As String = "C4"
' Destination
Const dName As String = "Sheet2"
Const dFirstCellAddress As String = "A1"
' Both
Const FixedColumnsCount As Long = 4
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the current region starting with the first cell.
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim sFirstCell As Range: Set sFirstCell = sws.Range(sFirstCellAddress)
Dim srg As Range
With sFirstCell.CurrentRegion
Set srg = sFirstCell.Resize(.Row + .Rows.Count - sFirstCell.Row, _
.Column + .Columns.Count - sFirstCell.Column)
End With
' Using 'GetTransformOneValuePerRow', return the transformed data
' in a 2D one-based array.
Dim Data As Variant
Data = GetTransformOneValuePerRow(srg, FixedColumnsCount)
If IsEmpty(Data) Then
MsgBox "An error occurred.", vbCritical
Exit Sub
End If
' Write to the destination range and clear below.
Dim rCount As Long: rCount = UBound(Data, 1)
With wb.Worksheets(dName).Range(dFirstCellAddress).Resize(, UBound(Data, 2))
.Resize(rCount).Value = Data
.Resize(.Worksheet.Rows.Count - .Row - rCount + 1).Offset(rCount).Clear
End With
MsgBox "Data transformed.", vbInformation
End Sub
Function GetTransformOneValuePerRow( _
ByVal SourceRange As Range, _
Optional ByVal FixedColumnsCount As Long = 1, _
Optional ByVal IncludeBlanks As Boolean = False) _
As Variant
Const ProcName As String = "GetTransformOneValuePerRow"
On Error GoTo ClearError
Dim sData As Variant ' Source Array
Dim srCount As Long ' Source Rows Count
Dim cCount As Long ' Source/Destination Columns Count
Dim drCount As Long ' Destination Rows Count
With SourceRange
srCount = .Rows.Count
cCount = .Columns.Count
With .Resize(srCount - 1, cCount - FixedColumnsCount) _
.Offset(1, FixedColumnsCount - 1) ' Values Range
drCount = .Rows.Count * .Columns.Count + 1
If Not IncludeBlanks Then _
drCount = drCount - Application.CountBlank(.Cells)
End With
sData = .Value
End With
Dim dData As Variant: ReDim dData(1 To drCount, 1 To cCount) ' Dest. Array
Dim fvCol As Long: fvCol = FixedColumnsCount + 1 ' First Value Column
Dim dr As Long: dr = 1 ' Destination Row
Dim sr As Long ' Source Row
Dim fc As Long ' Fixed Column
Dim vc As Long ' Value Column
' Write headers.
For fc = 1 To cCount
dData(dr, fc) = sData(1, fc)
Next fc
' Write rest.
If IncludeBlanks Then ' all
For sr = 2 To srCount
For vc = fvCol To cCount
dr = dr + 1
dData(dr, vc) = sData(sr, vc)
For fc = 1 To FixedColumnsCount
dData(dr, fc) = sData(sr, fc)
Next fc
Next vc
Next sr
Else ' non-blank
For sr = 2 To srCount
For vc = fvCol To cCount
If Len(CStr(sData(sr, vc))) > 0 Then
dr = dr + 1
dData(dr, vc) = sData(sr, vc)
For fc = 1 To FixedColumnsCount
dData(dr, fc) = sData(sr, fc)
Next fc
End If
Next vc
Next sr
End If
GetTransformOneValuePerRow = dData
ProcExit:
Exit Function
ClearError:
Debug.Print "'" & ProcName & "' Run-time error '" _
& Err.Number & "':" & vbLf & " " & Err.Description
Resume ProcExit
End Function
My Intention:
I wanna select all values in Rows "B" and "C" and move these 1 and 2 steps up.
The Example for what I have:
A
B
C
AA
Two
AA
Three
Two
AA
Three
Two
Three
X
yy
CC
The Example for what I would: If in Column-A find "X" should YY and CC delet
A
B
C
AA
Two
Three
AA
Two
Three
AA
Two
Three
My Code:
Sub test()
ActiveSheet.Select
Range("B:B").Select Shift:=xlUp, CopyOrigin:=xlFormatFromLeftOrAbove
Range("C:C").Select Shift:=xlUp, CopyOrigin:=xlFormatFromLeftOrAbove
End Sub
I would be happy if somebody help me
Align Data
Option Explicit
Sub AlignData()
Const Cols As String = "A:C"
Const fRow As Long = 1
Const ExceptionsList As String = "XX" ' comma-separated, no spaces!
Const Gap As Long = 1 ' number of empty rows in-between
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
' Reference the source range.
Dim srg As Range
Dim srCount As Long
With ws.Rows(fRow).Columns(Cols).Resize(ws.Rows.Count - fRow + 1)
Dim lrCell As Range
Set lrCell = .Find("*", , xlFormulas, , xlByRows, xlPrevious)
If lrCell Is Nothing Then Exit Sub ' no data
srCount = lrCell.Row - fRow + 1
Set srg = .Resize(srCount)
End With
Dim cCount As Long: cCount = srg.Columns.Count
' 1 to hold each column array
' 2 to hold a collection of each column's matching values
Dim jArr As Variant: ReDim jArr(1 To cCount, 1 To 2)
Dim Exceptions() As String: Exceptions = Split(ExceptionsList, ",")
Dim crg As Range
Dim c As Long
Dim r As Long
Dim sValue As Variant
' Write the column arrays to the jagged array.
For c = 1 To cCount
jArr(c, 1) = srg.Columns(c).Value ' column arrays
Set jArr(c, 2) = New Collection ' to hold the matching values
Next c
' Use a dictionary to hold the indexes of (unwanted) exception matches.
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
Dim dStep As Long: dStep = Gap + 1
Dim dData As Variant
Dim drCount As Long
Dim dr As Long
Dim sr As Long
For c = 1 To cCount
dr = 0
For sr = 1 To srCount
sValue = jArr(c, 1)(sr, 1)
If Not IsEmpty(sValue) Then ' exclude empty values
dr = dr + 1
If c = 1 Then ' 1st array
If IsError(Application.Match(sValue, Exceptions, 0)) Then
jArr(c, 2).Add sValue
Else ' found in exceptions
dict(dr) = Empty ' add the index
End If
Else ' all but the 1st array
If Not dict.Exists(dr) Then
jArr(c, 2).Add sValue
End If
End If
End If
Next sr
' Write the values from the collection to the destination array.
If c = 1 Then
drCount = jArr(c, 2).Count * dStep - 1
ReDim dData(1 To drCount, 1 To cCount)
End If
For sr = 1 To drCount Step dStep
dData(sr, c) = jArr(c, 2)(Int(sr / dStep) + 1)
Next sr
Set jArr(c, 2) = Nothing
Next c
' Write the values from the destination array to the range and clear below.
With srg.Resize(drCount)
.Value = dData
.Resize(ws.Rows.Count - .Row - drCount + 1).Offset(drCount).Clear
End With
End Sub
select all cells (A1:C5) and start the following macro
Sub FillCells()
Dim rngCell As Range
Do Until Application.WorksheetFunction.CountBlank(Selection) = 0
For Each rngCell In Selection
If rngCell.Value = "" Then
rngCell.Value = rngCell.Offset(1, 0).Value
End If
Next rngCell
Loop
End Sub
Best regards
Bernd
I currently have two spreadsheets: one that pulls data from a SQL Server and is a data dump and one that needs to have those values populated into them. For the sake of simplicity, I've compiled a mini prototype to use for the purpose of my question. Things to note, the data dump sheet will have a varying amount of rows, however the columns will be static which should hopefully make for easy mapping. What I need my macro to be able to accomplish is to
Check if an ID value matches the one directly below it, if so
Check if the Spouse_Indicator field has an "N" or "Y" value
If the indicator is an "N" value then I need the corresponding rows from the employer and title fields to be populated into the student table
If the indicator is a "Y" value then I need the corresponding rows from the employer and title fields to be populated into the spouse table
If there is a sequence where the ID does not match the one directly below it, the data automatically gets populated into the student table
The problem that I am having with the way that my macro is set up is that only the most recent ID with a "N" indicator is getting populated into every cell of the student table whereas I need only unique values to be populated until the last ID has been read. The image attached shows a small sample size of the data, the first table shows what my macro is producing while the last table shows my target. I am also including my code to show what I've gotten so far. Let me know if I need to clarify anything, thanks a bunch.
Sub test2()
Dim wb As Workbook
Dim ws As Worksheet
Dim id As Range
Dim cell As Range
Dim student_employer As Range
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet1")
Set id = ws.Range("A2:A" & Cells(Rows.Count, "A").End(xlUp).Row)
Set student_employer = ws.Range("G3:G8")
For Each cell In id
If cell.Value = cell.Offset(1, 0).Value And cell.Offset(0, 1).Value = "N" Then
cell.Offset(0, 2).Copy student_employer.Cells
End If
Next
MsgBox ("DONE")
End Sub
I've edited my code and it is somewhat capturing what I am trying to accomplish, however I need the values to be pasted into the next empty cell, while mine currently skips the amount of cells depending on when the next copy-paste takes place.
Sub test2()
Dim id As Long
Dim x As Long
Dim emp As Range
Set emp = Range("G3:G8")
id = Cells(Rows.Count, "A").End(xlUp).Row
For x = 2 To id
If Cells(x, 1).Value = Cells(x, 1).Offset(1, 0) Then
Cells(x, 1).Offset(0, 2).Copy Cells(x, 6).Offset(1, 0)
End If
Next x
MsgBox ("DONE")
End Sub
Copy Unique Rows
Adjust the values in the constants section. If you feel like it, use the out-commented constants and sCols to get rid of the 'magic' numbers (1, 2, 3, 4).
For the sake of simplicity, it is assumed that the source data starts in cell A1 (CurrentRegion).
Option Explicit
Sub test1()
Const sName As String = "Sheet1"
'Const sCritCol As Long = 2
'Const sColsList As String = "1,3,4"
'Const scCount As Long = 4
Const sCrit1 As String = "N"
Const sCrit2 As String = "Y"
Const dName As String = "Sheet1"
Const dFirst As String = "F1"
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim srg As Range: Set srg = sws.Range("A1").CurrentRegion
If srg.Columns.Count <> 4 Then Exit Sub
Dim srCount As Long: srCount = srg.Rows.Count
If srCount = 1 Then Exit Sub
Dim sData As Variant: sData = srg.Value
'Dim sCols() As String: sCols = Split(sColsList, ",")
Dim dict1 As Object: Set dict1 = CreateObject("Scripting.Dictionary")
dict1.CompareMode = vbTextCompare
Dim dict2 As Object: Set dict2 = CreateObject("Scripting.Dictionary")
dict2.CompareMode = vbTextCompare
Dim cDat As Variant: ReDim cDat(1 To 3)
Dim Key As Variant
Dim sCrit As Variant
Dim r As Long
For r = 2 To srCount
sCrit = sData(r, 2)
Select Case UCase(CStr(sCrit))
Case sCrit1
Key = sData(r, 1)
If Not dict1.Exists(Key) Then
cDat(1) = sData(r, 1)
cDat(2) = sData(r, 3)
cDat(3) = sData(r, 4)
dict1(Key) = cDat
End If
Case sCrit2
Key = sData(r, 1)
If Not dict2.Exists(Key) Then
cDat(1) = sData(r, 1)
cDat(2) = sData(r, 3)
cDat(3) = sData(r, 4)
dict2(Key) = cDat
End If
End Select
Next r
Dim drCount As Long: drCount = dict1.Count + dict2.Count + 4
Dim dData As Variant: ReDim dData(1 To drCount, 1 To 3)
r = 1
dData(r, 1) = "student"
r = r + 1
dData(r, 1) = sData(1, 1)
dData(r, 2) = sData(1, 3)
dData(r, 3) = sData(1, 4)
Dim n As Long
If dict1.Count > 0 Then
For Each Key In dict1.Keys
r = r + 1
For n = 1 To 3
dData(r, n) = dict1(Key)(n)
Next n
Next Key
End If
r = r + 1
dData(r, 1) = "spouse"
r = r + 1
dData(r, 1) = sData(1, 1)
dData(r, 2) = sData(1, 3)
dData(r, 3) = sData(1, 4)
If dict2.Count > 0 Then
For Each Key In dict2.Keys
r = r + 1
For n = 1 To 3
dData(r, n) = dict2(Key)(n)
Next n
Next Key
End If
Application.ScreenUpdating = False
' Write.
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim drg As Range: Set drg = dws.Range(dFirst).Resize(r, 3)
drg.Clear ' because of merged cells
drg.Value = dData
' Clear below.
Dim crg As Range
Set crg = drg.Resize(dws.Rows.Count - drg.Row - r + 1).Offset(r)
crg.Clear
' Format 'student'
With drg.Rows(1)
.Cells(1).Font.Bold = True
.MergeCells = True
.HorizontalAlignment = xlCenter
.BorderAround xlContinuous, xlThick
End With
' Format 'spouse'.
With drg.Rows(dict1.Count + 3)
.Cells(1).Font.Bold = True
.MergeCells = True
.HorizontalAlignment = xlCenter
.BorderAround xlContinuous, xlThick
End With
' Format all.
drg.EntireColumn.AutoFit
Application.ScreenUpdating = True
MsgBox ("DONE")
End Sub