Copy a range into a single column - values only - vba

Hello I am trying to copy a range into a single column. The range is a mix of blank cells and cells with values.I only want to copy and paste the cells with values and I would it to find the first blank cell and want it to walk itself down the column from there.
The code I have right now (besides taking forever) pastes in the first row.
Dim i As Integer
i = 1
ThisWorkbook.Worksheets("amount date").Select
For Row = 51 To 100
For col = 2 To 1000
If Cells(Row, col).Value <> "" Then
Cells(Row, col).Copy
Worksheets("sheet 2").Range("G" & i).PasteSpecial xlPasteValues
End If
Next
Next
Do While Worksheets("sheet 2").Range("G" & i).Value <> ""
i = i + 1
Loop
End Sub

This will work:
Sub qwerty()
Dim i As Long, r As Long, c As Long
i = 1
ThisWorkbook.Worksheets("amount date").Select
For r = 51 To 100
For c = 2 To 1000
If Cells(r, c).Value <> "" Then
Cells(r, c).Copy
Worksheets("sheet 2").Range("G" & i).PasteSpecial xlPasteValues
i = i + 1
End If
Next
Next
End Sub

Perhaps this will be a little faster (even though it seems to have been slow arriving).
Sub CopyRangeToSingleColumn()
' 20 Oct 2017
Dim LastRow As Long
Dim LastClm As Long
Dim Rng As Range, Cell As Range
Dim CellVal As Variant
Dim Spike(), i As Long
With ThisWorkbook.Worksheets("amount date")
With .UsedRange.Cells(.UsedRange.Cells.Count)
LastRow = Application.Max(Application.Min(.Row, 100), 51)
LastClm = .Column
End With
Set Rng = .Range(.Cells(51, "A"), .Cells(LastRow, LastClm))
End With
ReDim Spike(Rng.Cells.Count)
For Each Cell In Rng
CellVal = Trim(Cell.Value) ' try to access the sheet less often
If CellVal <> "" Then
Spike(i) = CellVal
i = i + 1
End If
Next Cell
If i Then
ReDim Preserve Spike(i)
With Worksheets("sheet 2")
LastRow = Application.Max(.Cells(.Rows.Count, "G").End(xlUp).Row, 2)
.Cells(LastRow, "G").Resize(UBound(Spike)).Value = Application.Transpose(Spike)
End With
End If
End Sub
The above code was modified to append the result to column G instead of over-writing existing cell values.

Do you need copy the whole row into one cell, row by row? For each loop shall be faster. I guess, this should work
Sub RowToCell()
Dim rng As Range
Dim rRow As Range
Dim rRowNB As Range
Dim cl As Range
Dim sVal As String
Set rng = Worksheets("Sheet3").Range("$B$51:$ALN$100") 'check this range
For Each rRow In rng.Rows
On Error Resume Next
Set rRowNB = rRow.SpecialCells(xlCellTypeConstants)
Set rRowNB = Union(rRow.SpecialCells(xlCellTypeFormulas), rRow)
On Error GoTo 0
For Each cl In rRowNB.Cells
sVal = sVal & cl.Value
Next cl
Worksheets("sheet4").Range("G" & rRow.Row - 50).Value = sVal
sVal = ""
Next rRow
End Sub
its quick for this range.

Related

Set keywords in VBA based on multiple columns with dynamic ranges

I need to set some keywords based on multiple columns. I currently use this code which works well for one column:
Dim Words As range
Set Words = Sheets("Words").range("A2").Resize(Sheets("Words").range("A" & Rows.Count).End(xlUp).Row - 1)
But if I extend this to, say, A:AT it doesn't work.
Basically all I want to do is store all the words in ranges A2:Ax all the way to AT2:ATx but the issue is that each column has a different number of words that need to be stored.
EDIT: As requested, my full code as it currently stands
Sub Keyword()
Application.ScreenUpdating = False
Dim Words As range
Dim strText As range
Dim c As range
Dim r As range
Set Words = Sheets("Words").range("A2:AT2").Resize(Sheets("Words").range("A" & Rows.Count).End(xlUp).Row - 1)
Set strText = Sheets("Verbatims").range("BJ2").Resize(Sheets("Verbatims").range("BJ" & Rows.Count).End(xlUp).Row - 1)
For Each c In strText
For Each r In Words
If InStr(1, UCase(c), UCase(r), 1) > 0 Then
c.Offset(, 29) = c.Offset(, 29) & ", " & r
End If
Next r
If Len(c.Offset(, 29)) > 0 Then c.Offset(, 29) = Right(c.Offset(, 29), (Len(c.Offset(, 29)) - 2))
Next c
Application.ScreenUpdating = True
End Sub
EDIT2: Thanks to #jamheadart I've updated my code and it works now.
Sub Keywords()
Dim WordsRange As range
Dim hRow As Long
Dim i As Long
With Worksheets("Words")
For i = 1 To 46
If hRow < Cells(Rows.Count, i).End(xlUp).Row Then hRow = Cells(Rows.Count, i).End(xlUp).Row
Next i
Set WordsRange = range("A2:AT" & hRow)
End With
Dim c As range
Dim Words As Collection
Set Words = New Collection
For Each c In WordsRange
If c.Value <> "" Then Words.Add c.Value
Next
Dim strText As range
Dim x As range
Dim r As Variant
Set strText = Sheets("Verbatims").range("BJ2").Resize(Sheets("Verbatims").range("BJ" & Rows.Count).End(xlUp).Row - 1)
For Each x In strText
For Each r In Words
If InStr(1, UCase(x), UCase(r), 1) > 0 Then
x.Offset(, 29) = x.Offset(, 29) & ", " & r
End If
Next r
If Len(x.Offset(, 29)) > 0 Then x.Offset(, 29) = Right(x.Offset(, 29), (Len(x.Offset(, 29)) - 2))
Next x
End Sub
I think you need to loop through columns 1 to 46 (AT) and find the maximum row, I wouldn't normally rely on UsedRange because it can sometimes not register updates on sheets but I suspect you aren't writing a massive long thread.
Sub eh()
Dim WordsRange As Range
Dim hRow As Long
Dim i As Long
For i = 1 To 46
If hRow < Cells(Rows.Count, i).End(xlUp).Row Then hRow = Cells(Rows.Count, i).End(xlUp).Row
Next i
Set WordsRange = Range("A2:AT" & hRow)
MsgBox (WordsRange.Address)
End Sub
Maybes you then want to put everything that's not a "" in to a list of key words to check against rather than checking against the range?
Dim c as Range
Dim Words as Collection
For Each c In WordsRange
If c.Value2 <> "" Then Words.Add c.Value2
Next
may be you're after this
Dim Words As Range
With Worksheets("Words")
With Intersect(.Range("A:AT"), .UsedRange)
Set Words = .Resize(.Rows.Count - 1).Offset(1, 0).SpecialCells(xlCellTypeConstants)
End With
End With
Try,
Dim Words As range
with workSheets("Words")
with intersect(.range("A:AT"), .usedrange)
Set Words = .resize(.rows.count-1, .columns.count).offset(1, 0)
end with
end with
If you want to avoid blanks, create a Union.
Dim Words As range, i as long
with workSheets("Words")
set words = .range(.cells(2, "A"), .cells(.rows.count, "A").end(xlup))
for i=2 to .columns("AT").column
set words = Union(words, .range(.cells(2, i), .cells(.rows.count, i).end(xlup))
next i
end with
To cycle through that Union you will likely have to deal with the Range.Areas property.

Excel VBA import multiple matches into different columns same row

I'm trying to import cells from another wb. So if cell in wb1 col H matches cell in wb2 col K then wb1 col k and L = wb2 col C and E in match row. Now there may be several matches so I want it to offset to the next column. m and n for next set, o and p for next, and so on.
This is what I have so far:
Private Sub CommandButton1_Click()
Dim rcell As Range, sValue As String
Dim lcol As Long, cRow As Long
Dim dRange As Range, sCell As Range
Dim LastRow As Integer
Dim CurrentRow As Integer
Set ws1 = ThisWorkbook
Set ws2 = Workbooks("Workbook2").Worksheets("Sheet1")
Sheet1LastRow = ThisWorkbook.Sheets("Data").Range("H2:H50000").Value 'Search criteria column
Sheet2LastRow = Workbooks("Workbook2").Worksheets("Sheet1").Range("Q" & Rows.Count).End(xlUp).Row 'Where to look for matches
With Workbooks("Workbook2").Worksheets("Sheet1")
For j = 1 To Sheet1LastRow
For i = 1 To Sheet2LastRow
If ThisWorkbook.Sheets("Data").Range("H").Value = ws2.Cells(i, 11).Value Then
ws2.Cells(i, 11).Value = ThisWorkbook.Sheets("Data").Range("C").Value
ws2.Cells(i, 12).Value = ThisWorkbook.Sheets("Data").Range("E").Value
End If
If InStr(1, ws2.Cells.Value, ws1.Cells.Value) And Trim(ws1.Cells.Value) <> "" Then
rcell.Offset(0, lcol).Value = ws2.Cells.Offset(0, 2).Value
lcol = lcol + 1
End If
Next i
Next j
End With
End Sub
This doesn't work. I basically gave up since I don't know what I'm missing.
I looked for something like this but only found something a Vlookup or Match could do.
You can do it by keeping track of an offset that you shift by two after each match copied. I'll track this in a variable called offs.
Also I suppose that the copying goes from wb2 to wb1 as described in the text, not as "suspected" in the code.
Private Sub CommandButton1_Click()
Dim cel1 As Range, cel2 As Range
For Each cel1 In ThisWorkbook.Sheets("Data").UsedRange.Columns("H").Cells
Dim offs As Long: offs = 3 ' <-- Initial offset, will increase by 2 after each match
For Each cel2 In Workbooks("Workbook2").Worksheets("Sheet1").UsedRange.Columns("K").Cells
If cel1.Value = cel2.Value Then
cel1.offset(, offs).Value = cel2.offset(, -8).Value ' <- wb2(C) to wb1(K)
cel1.offset(, offs + 1).Value = cel2.offset(, -6).Value ' <- wb2(E) to wb1(L)
offs = offs + 2 ' <-- now shift the destination column by 2 for next match
End If
Next
Next
End Sub

Macro that Delete a Row on a Sheet based on another Sheet

I have a macro that consolidate the values on another sheet, and based on these values, it´s has to go back on the first sheet and delete.
The sheet it´s like this, if the value on the G2 it´s (Manter a linha), it´s get the number of the row on the F2, and goes to delete the previews of the row.
Else, goes to I2, and do the same.
Thank you for your help and time.
Sheet
I have this so far:
Sub Delete()
Range("G2").Select
Do Until IsEmpty(ActiveCell)
Range("G" & Rows.Count).Select
If Range("G" & 2).Value = ("<<<Manter a linha") Then
Sheets("Controle Estoque Fixo").Select
Rows("2:5").Select
Selection.EntireRow.Delete
End If
Loop
EDIT:
Dim r1 As Range, c As Range
Dim s As String
Dim v As String
Dim k As String
Dim t As String
k = "1"
Set r1 = Range(Cells(2, "H"), Cells(Rows.Count, "H").End(xlUp))
v = Sheets("Analise de Estoque").Cells(2, "G").Value
For Each c In r1
If c.Text = ("<<<Manter a linha") Then
Sheets("Controle Estoque Fixo").Select
t = (v - 1)
Rows(t).Select.Clear
End If
Next
End Sub
Now I can go back and select the value of the cell that contains the row, that I want to keep, so I add a "- 1" to select before that, but I tried to add the begging and won´t work(tried to add T as a string and put = 1)
You need to build your range and delete all the rows at once.
Sub DeleteMatches()
Dim r1 As Range, c As Range
Dim s As String
Set r1 = Range(Cells(2, "G"), Cells(Rows.Count, "G").End(xlUp))
For Each c In r1
If c = "<<<Manter a linha" Then
If Len(s) Then s = s & ","
s = s & "A" & c.Offset(0, -1)
End If
Next
If Len(s) Then
s = Left(s, Len(s) - 1)
Sheets("Controle Estoque Fixo").Range(s).EntireRow.Delete
End If
End Sub
If you only want to clear the rows and not delete then them then you can do it your way.
Sub DeleteMatches2()
Dim r1 As Range, c As Range
Dim t As String
With Sheets("Analise de Estoque")
Set r1 = .Range(.Cells(2, "H"), .Cells(Rows.Count, "H").End(xlUp))
End With
For Each c In r1
If c.Text = "<<<Manter a linha" Then
Sheets("Controle Estoque Fixo").Select
t = c.Offset(0, -1)
Rows(t).ClearContents
End If
Next
End Sub
Sub DeleteMatches3()
Dim r1 As Range, c As Range
Dim i As Long, LastRow As Long
Dim t As String
With Sheets("Analise de Estoque")
LastRow = .Cells(Rows.Count, "H").End(xlUp)
For i = 2 To LastRow
If .Cells(i, "G").Text = "<<<Manter a linha" Then
t = .Cells(i, "F").Text
Sheets("Controle Estoque Fixo").Rows(t).ClearContents
End If
Next
End With
End Sub
Just remember that when you delete rows you have to go from the last row to the first
For i = LastRow To 2 Step - 1
Next

Find all numbers in specified intervals [Min; Max] and write them in one column

I have a problem with a specific excel task. Although I searched the web thoroughly for tips and parts of code I could use, I was not able to get near a functioning solution.
This is my problem:
I have around 30 Worksheets with two columns each.
The number of Rows varies from WS to WS but the two columns on each sheet are equally long.
The first column of each Sheet contains minimum values and the second column holds the respective maximum values.
E.g.
| A | B
1 | 1000 | 1010
2 | 2020 | 2025
Now I need one single column with all values from these intervals including the Max and Min values.
Preferred solution in Column C:
1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 2020, 2021, 2022, 2023, 2024, 2025
I thought of highlighting the two columns and then activating a macro to generate the list. I would then repeat this process for each WS manually. Some sheets have only 4 to 20 rows but some have over 7000 rows.
And if it helps anything: The numbers are postcodes ;-)
I'd be very grateful for any kind of help.
Thanks in advance!
Try this:
Sub Test()
Dim LastRow As Long, ColIndex As Long
Dim i As Long, j As Long
Dim min As Long, max As Long
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
LastRow = ws.Cells(Rows.Count, "A").End(xlUp).Row
ColIndex = 1
For i = 1 To LastRow
min = ws.Cells(i, 1).Value
max = ws.Cells(i, 2).Value
For j = min To max
ws.Cells(ColIndex, 3).Value = j
ColIndex = ColIndex + 1
Next j
Next i
Next ws
End Sub
edited: to have one big string in column "C" (added two lines in each code)
edited 2: added "zip3" solution for having all values listed in "C" column only
you could use either following ways
Option Explicit
Sub zips3()
'list values in column "C" in sequence from all min to max in columns "A" and "B"
Dim sht As Worksheet
Dim cell As Range
For Each sht In ThisWorkbook.Sheets
For Each cell In sht.Range("A1:A" & sht.Cells(sht.Rows.Count, 1).End(xlUp).Row).SpecialCells(xlCellTypeConstants, xlNumbers)
With cell.End(xlToRight).Offset(, 2).Resize(, cell.Offset(, 1).Value - cell.Value + 1)
.FormulaR1C1 = "=RC1+COLUMN()-4"
sht.Range("C" & sht.Cells(sht.Rows.Count, "C").End(xlUp).Row).Offset(1).Resize(.Columns.Count) = Application.Transpose(.Value)
.ClearContents
End With
Next cell
If IsEmpty(sht.Range("C1")) Then sht.Range("C1").Delete (xlShiftUp)
Next sht
End Sub
Sub zips()
'list values in column "C" from corresponding min to max in columns "A" and "B"
Dim sht As Worksheet
Dim cell As Range
Dim j As Long
For Each sht In ThisWorkbook.Sheets
For Each cell In sht.Range("A1:A" & sht.Cells(sht.Rows.Count, 1).End(xlUp).Row).SpecialCells(xlCellTypeConstants, xlNumbers)
For j = cell.Value To cell.Offset(, 1).Value
cell.End(xlToRight).Offset(, 1) = j
Next j
'lines added to have one bg string in column "C"
cell.Offset(, 2).Value2 = "'" & Join(Application.Transpose(Application.Transpose(Range(cell.Offset(, 2), cell.Offset(, 2).End(xlToRight)))), ",")
Range(cell.Offset(, 3), cell.Offset(, 3).End(xlToRight)).ClearContents
Next cell
Next sht
End Sub
Sub zips2()
Dim sht As Worksheet
Dim cell As Range
For Each sht In ThisWorkbook.Sheets
For Each cell In sht.Range("A1:A" & sht.Cells(sht.Rows.Count, 1).End(xlUp).Row).SpecialCells(xlCellTypeConstants, xlNumbers)
cell.End(xlToRight).Offset(, 1).Resize(, cell.Offset(, 1).Value - cell.Value + 1).FormulaR1C1 = "=RC1+COLUMN()-3"
'lines added to have one bg string in column "C"
cell.Offset(, 2).Value2 = "'" & Join(Application.Transpose(Application.Transpose(Range(cell.Offset(, 2), cell.Offset(, 2).End(xlToRight)))), ",")
Range(cell.Offset(, 3), cell.Offset(, 3).End(xlToRight)).ClearContents
Next cell
Next sht
End Sub
A solution you can use as you like would be kinda like this:
Public Function getZIPs(rng As Range) As String
Dim myVal As Variant, str As String, i As Long, j As Long
myVal = Intersect(rng, rng.Parent.UsedRange).Value
For i = 1 To UBound(myVal)
If IsNumeric(myVal(i, 1)) And IsNumeric(myVal(i, 2)) And Len(myVal(i, 1)) > 0 And Len(myVal(i, 2)) > 0 Then
If myVal(i, 1) <= myVal(i, 2) Then
For j = myVal(i, 1) To myVal(i, 2)
str = str & ", " & j
Next
End If
End If
Next
getZIPs = Mid(str, 3)
End Function
Put this into a module and then either go for C1: =getZIPs(A1:B1) and auto fill down or directly =getZIPs(A:B) to get all numbers in one cell or use it in a sub to do it automatically.
If you have any questions, just ask :)
EDIT:
If you want it all exactly in the one-column-way, you can use this (should be fast):
Sub getMyList()
Dim sCell As Range, gCell As Range
Set gCell = ActiveSheet.[A1:B1]
Set sCell = ActiveSheet.[C1]
Dim sList As Variant
While IsNumeric(gCell(1)) And IsNumeric(gCell(2)) And Len(gCell(1)) > 0 And Len(gCell(2)) > 0
If gCell(1) = gCell(2) Then
sCell.Value = gCell(1)
Set sCell = sCell.Offset(1)
Else
sList = Evaluate("ROW(" & gCell(1) & ":" & gCell(2) & ")")
sCell.Resize(UBound(sList)).Value = sList
Set sCell = sCell.Offset(UBound(sList))
End If
Set gCell = gCell.Offset(1)
Wend
End Sub
If you have any questions, just ask ;)

how to insert a row before pasting an array

I currently have an array which I populate and paste in a sheet named "T1" using a macro. My current macro uses the rowcount function to determine the used rows and pastes the array from the next available row.
The problem I am having is that when I paste this array multiple times, the arrays need to be spaced by a row so that i can differentiate different submissions. This is what I have so far, and I was hoping someone could help me with this:
Sub CopyData()
Dim Truearray() As String
Dim cell As Excel.Range
Dim RowCount1 As Integer
Dim i As Integer
Dim ii As Integer
Dim col As Range
Dim col2 As Range
i = 0
ii = 2
RowCount1 = DHRSheet.UsedRange.Rows.Count
Set col = DHRSheet.Range("I1:I" & RowCount1)
For Each cell In col
If cell.Value = "True" Then
Dim ValueCell As Range
Set ValueCell = Cells(cell.Row, 3)
ReDim Preserve Truearray(i)
Truearray(i) = ValueCell.Value
Dim siblingCell As Range
Set siblingCell = Cells(cell.Row, 2)
Dim Siblingarray() As String
ReDim Preserve Siblingarray(i)
Siblingarray(i) = DHRSheet.Name & "$" & siblingCell.Value
i = i + 1
End If
Next
Dim RowCount2 As Integer
RowCount2 = DataSheet.UsedRange.Rows.Count + 1
For ii = 2 To UBound(Truearray)
DataSheet.Cells(RowCount2 + ii, 2).Value = Truearray(ii)
Next
For ii = 2 To UBound(Siblingarray)
DataSheet.Cells(RowCount2 + ii, 1).Value = Siblingarray(ii)
Next
DataSheet.Columns("A:B").AutoFit
MsgBox ("Data entered has been successfully validated & logged")
End Sub
If you Offset two rows from the bottom cell, you will leave a blank row of separation. You should also consider filling the whole array as base 1 and writing it to DataSheet in one shot.
Sub CopyData2()
Dim rCell As Range
Dim aTrues() As Variant
Dim rRng As Range
Dim lCnt As Long
'Define the range to search
With DHRSheet
Set rRng = .Range(.Cells(1, 9), .Cells(.Rows.Count, 9).End(xlUp))
End With
'resize array to hold all the 'trues'
ReDim aTrues(1 To Application.WorksheetFunction.CountIf(rRng, "True"), 1 To 2)
For Each rCell In rRng.Cells
If rCell.Value = "True" Then
lCnt = lCnt + 1
'store the string from column 2
aTrues(lCnt, 1) = DHRSheet.Name & "$" & rCell.Offset(0, -7).Value
'store the value from column 3
aTrues(lCnt, 2) = rCell.Offset(0, -6).Value
End If
Next rCell
'offset 2 from the bottom row to leave a row of separation
With DataSheet.Cells(DataSheet.Rows.Count, 1).End(xlUp).Offset(2, 0)
'write the stored information at one time
.Resize(UBound(aTrues, 1), UBound(aTrues, 2)).Value = aTrues
End With
End Sub