Iterate over defined lists in excel - excel

I have an excel spreadsheet, with two defined lists. Call them colours{red, green, blue} and types{1, 2}
I have a function to calculate for each object, so finally, I have a table that looks like
colour type result
red 1 100
red 2 200
green 1 150
green 2 250
blue 1 155
blue 2 255
But obviously I wrote that by hand. Without using a VB script, is there any way I can get excel to fill in the colour and type cells to enumerate the whole set?
Thanks

Here's one VBA approach - you can pass in as many lists (by range) as you like and it will create all the combinations and copy them to where you specify.
Sub tester()
'First range is where to place the results, next ranges
' are the lists to be combined
SqlPermutate Sheet1.Range("E1"), Sheet1.Range("A1:A20"), _
Sheet1.Range("B1:B5"), Sheet1.Range("C1:C10")
End Sub
Sub SqlPermutate(rngDestination As Range, ParamArray ranges() As Variant)
Dim oConn As Object, oRS As Object
Dim sPath, i As Long, srcWb As Workbook
Dim sSQL As String, flds As String, tbls As String
'check source ranges are in a saved workbook...
Set srcWb = ranges(0).Parent.Parent
If srcWb.Path <> "" Then
sPath = srcWb.FullName
Else
MsgBox "Workbook being queried must be saved first..."
Exit Sub
End If
For i = LBound(ranges) To UBound(ranges)
flds = flds & IIf(Len(flds) > 0, ",", "") & Chr(65 + i) & ".*"
tbls = tbls & IIf(Len(tbls) > 0, ",", "") & _
RngNm(ranges(i)) & " " & Chr(65 + i)
Next i
sSQL = "select " & flds & " from " & tbls
Debug.Print sSQL
Set oConn = CreateObject("adodb.connection")
Set oRS = CreateObject("ADODB.Recordset")
oConn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" & sPath & "';" & _
"Extended Properties='Excel 12.0;HDR=no;IMEX=1';"
oRS.Open sSQL, oConn
If Not oRS.EOF Then
rngDestination.CopyFromRecordset oRS
Else
MsgBox "No records found"
End If
oRS.Close
oConn.Close
End Sub
Function RngNm(r) As String
RngNm = "[" & r.Parent.Name & "$" & _
r.Address(False, False) & "]"
End Function

Related

Copy data from closed workbook to another open workbook in VBA?

I know this has probably been asked before but I was wondering if it was possible to copy data from another 'closed' workbook to my current open workbook. If tried to look up some things and everywhere says it is not possible... I know it's a bit of an open ended question.
Ah, this takes me back a few years. I believe this was done by Ron years ago (explained on a different platform). But there are two ways to do it. One method I forgot and gets the cells one by one and the other is the ADO method posted below. First there are two example subs (one method to bring headers and the other to not) and then followed by the main ADO sub.
Option Explicit
Sub GetData_ExampleV1()
' It will copy the Header row also (the last two arguments are True)
' Change the last argument to False if you not want to copy the header row
GetData ThisWorkbook.Path & "\test.xlsx", "Sheet1", _
"A1:C5", Sheets("Sheet1").Range("A1"), True, True
End Sub
Sub GetData_ExampleC2()
' It will not copy the Header row (the last two arguments are True, False)
' Change the last argument to True if you also want to copy the header row
GetData ThisWorkbook.Path & "\test.xlsx", "Sheet1", _
"A1:C5", Sheets("Sheet1").Range("A1"), True, False
End Sub
This is the ADO (function) you call to do it.
Public Sub GetData(SourceFile As Variant, SourceSheet As String, _
SourceRange As String, TargetRange As Range, Header As Boolean, UseHeaderRow As Boolean)
Dim rsCon As Object
Dim rsData As Object
Dim szConnect As String
Dim szSQL As String
Dim lCount As Long
' Create the connection string.
If Header = False Then
If Val(Application.Version) < 12 Then
szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=No"";"
Else
szConnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 12.0;HDR=No"";"
End If
Else
If Val(Application.Version) < 12 Then
szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes"";"
Else
szConnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 12.0;HDR=Yes"";"
End If
End If
If SourceSheet = "" Then
' workbook level name
szSQL = "SELECT * FROM " & SourceRange$ & ";"
Else
' worksheet level name or range
szSQL = "SELECT * FROM [" & SourceSheet$ & "$" & SourceRange$ & "];"
End If
On Error GoTo SomethingWrong
Set rsCon = CreateObject("ADODB.Connection")
Set rsData = CreateObject("ADODB.Recordset")
rsCon.Open szConnect
rsData.Open szSQL, rsCon, 0, 1, 1
' Check to make sure we received data and copy the data
If Not rsData.EOF Then
If Header = False Then
TargetRange.Cells(1, 1).CopyFromRecordset rsData
Else
'Add the header cell in each column if the last argument is True
If UseHeaderRow Then
For lCount = 0 To rsData.Fields.Count - 1
TargetRange.Cells(1, 1 + lCount).Value = _
rsData.Fields(lCount).Name
Next lCount
TargetRange.Cells(2, 1).CopyFromRecordset rsData
Else
TargetRange.Cells(1, 1).CopyFromRecordset rsData
End If
End If
Else
MsgBox "No records returned from : " & SourceFile, vbCritical
End If
' Clean up our Recordset object.
rsData.Close
Set rsData = Nothing
rsCon.Close
Set rsCon = Nothing
Exit Sub
SomethingWrong:
MsgBox "The file name, Sheet name or Range is invalid of : " & SourceFile, _
vbExclamation, "Error"
On Error GoTo 0
End Sub

Excel VBA Copy and Transpose data for every 3th row

I have this code to copy and transpose data. It only copy one column to one row. I want to copy data for every 3 row into multiple row. For example:
1 become 123
2 456
3
4
5
6
This is my code to copy and transpose data. How can I do it like example above? Thanks for the help
Public Sub GetData(SourceFile As Variant, SourceSheet As String, _
SourceRange As String, TargetRange As Range, Header As Boolean, UseHeaderRow As Boolean)
' 30-Dec-2007, working in Excel 2000-2007
Dim rsCon As Object
Dim rsData As Object
Dim szConnect As String
Dim szSQL As String
Dim lCount As Long
' Create the connection string.
If Header = False Then
If Val(Application.Version) < 12 Then
szConnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=No;"";"
Else
szConnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 12.0;HDR=No;"";"
End If
Else
If Val(Application.Version) < 12 Then
szConnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;"";"
Else
szConnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 12.0;HDR=Yes;"";"
End If
End If
If SourceSheet = "" Then
' workbook level name
szSQL = "SELECT * FROM " & SourceRange$ & ";"
Else
' worksheet level name or range
szSQL = "SELECT * FROM [" & SourceSheet$ & "$" & SourceRange$ & "];"
End If
On Error GoTo SomethingWrong
Set rsCon = CreateObject("ADODB.Connection")
Set rsData = CreateObject("ADODB.Recordset")
rsCon.Open szConnect
rsData.Open szSQL, rsCon, 0, 1, 1
' Check to make sure we received data and copy the data
If Not rsData.EOF Then
' Copy and Transpose data to destination
Dim vDB
vDB = rsData.getRows
If Header = False Then
TargetRange.Cells(1, 1).Resize(UBound(vDB, 1) + 1, UBound(vDB, 2) + 1) = vDB
Else
'Add the header cell in each column if the last argument is True
If UseHeaderRow Then
For lCount = 0 To rsData.Fields.Count - 1
TargetRange.Cells(1, 1 + lCount).Value = _
rsData.Fields(lCount).Name
Next lCount
TargetRange.Cells(2, 1).CopyFromRecordset rsData
Else
TargetRange.Cells(1, 1).CopyFromRecordset rsData
End If
End If
Else
MsgBox "No records returned from : " & SourceFile, vbCritical
End If
' Clean up our Recordset object.
rsData.Close
Set rsData = Nothing
rsCon.Close
Set rsCon = Nothing
Exit Sub
You can use this code to transpose every 3 numbers into one row. Not sure if this is what you mean.
Sheet:
1 123
2 456
3 789
4
5
6
7
8
9
Code:
Sub BlaBlaBla()
Number = vbNullString
Row = 1
Count = 0
For i = 1 To 9
Number = Number & CStr(Sheets(1).Range("A" & i))
Count = Count + 1
If Count = 3 Then
Count = 0
Sheets(1).Range("B" & Row) = Number
Number = vbNullString
Row = Row + 1
End If
Next i
End Sub

Adapt AutoCAD VBA to work in Excel

I have written a code (with help) that works in AutoCAD VBA but I'd like to adapt it so I can run it from Excel and integrate it into a longer macro. I've tried replacing ThisDrawing with ACAD.ActiveDocument but this isn't working. Here's my full AutoCAD VBA code:
Public Sub Section()
Dim SolidObject As Acad3DSolid
Dim NewRegionObject As AcadRegion
Dim PlaneOrigin As Variant
Dim PlaneXaxisPoint As Variant
Dim PlaneYaxisPoint As Variant
Dim PickedPoint As Variant
On Error Resume Next
With ThisDrawing.Utility
.GetEntity SolidObject, PickedPoint, vbCr & "Select solid to cut."
If Err Then
MsgBox "Selected solid must be a 3DSolid"
Exit Sub
End If
PlaneOrigin = .GetPoint(PickedPoint, vbCr & "Select point to define origin.")
PlaneXaxisPoint = .GetPoint(PickedPoint, vbCr & "Select point to define x-axis.")
PlaneYaxisPoint = .GetPoint(PickedPoint, vbCr & "Select point to define y-axis.")
Dim minPoint As Variant, maxPoint As Variant
Set NewRegionObject = SolidObject.SectionSolid(PlaneOrigin, PlaneXaxisPoint, PlaneYaxisPoint)
With NewRegionObject
MsgBox "Area: " & .Area
MsgBox "Perimeter: " & .Perimeter
.GetBoundingBox minPoint, maxPoint
MsgBox "Min Point coordinates: (" & minPoint(0) & "," & minPoint(1) & "," & minPoint(2) & ")"
MsgBox "Max Point coordinates: (" & maxPoint(0) & "," & maxPoint(1) & "," & maxPoint(2) & ")"
End With
End With
End Sub
you could use this function to see if there's a running instance of AutoCad and, if there is, get it:
Function Set_Acad(Acad As AcadApplication) As Boolean
On Error Resume Next
Set Acad = GetObject(, "AutoCAD.Application") 'Get a running instance of the class AutoCAD.Application
On Error GoTo 0
Set_Acad = Not Acad Is Nothing
End Function
to be exploited in your main code as follows:
Option Explicit
Public Sub Section()
Dim SolidObject As Acad3DSolid
Dim NewRegionObject As AcadRegion
Dim PlaneOrigin As Variant
Dim PlaneXaxisPoint As Variant
Dim PlaneYaxisPoint As Variant
Dim PickedPoint As Variant
Dim Acad As AcadApplication '<--| declare a variable of type 'AcadApplication'
If Not Set_Acad(Acad) Then Exit Sub '<--| exit if there's no Autocad running instance, otehrwise set 'Acad' variable to it
With Acad.ActiveDocument.Utility '<--| now you can use Acad to reference 'Autocad' application and all its objects/methods/properties
On Error Resume Next
.GetEntity SolidObject, PickedPoint, vbCr & "Select solid to cut."
If Err Then
MsgBox "Selected solid must be a 3DSolid"
Set Acad = Nothing
Exit Sub
End If
On Error GoTo 0
PlaneOrigin = .GetPoint(PickedPoint, vbCr & "Select point to define origin.")
PlaneXaxisPoint = .GetPoint(PickedPoint, vbCr & "Select point to define x-axis.")
PlaneYaxisPoint = .GetPoint(PickedPoint, vbCr & "Select point to define y-axis.")
Dim minPoint As Variant, maxPoint As Variant
Set NewRegionObject = SolidObject.SectionSolid(PlaneOrigin, PlaneXaxisPoint, PlaneYaxisPoint)
With NewRegionObject
MsgBox "Area: " & .area
MsgBox "Perimeter: " & .Perimeter
.GetBoundingBox minPoint, maxPoint
MsgBox "Min Point coordinates: (" & minPoint(0) & "," & minPoint(1) & "," & minPoint(2) & ")"
MsgBox "Max Point coordinates: (" & maxPoint(0) & "," & maxPoint(1) & "," & maxPoint(2) & ")"
End With
End With
Set Acad = Nothing
End Sub
Create a line in AutoCAD (must be opened) from Excel
But you have to go in Tools->References and add [AutoCAD 20xx Type Library]
Sub testline()
Dim app
Dim lineObj As AcadLine
Dim startPoint(0 To 2) As Double
Dim endPoint(0 To 2) As Double
On Error Resume Next
Set app = GetObject(, "AutoCAD.Application")
On Error GoTo 0
If (app Is Nothing) Then Exit Sub
startPoint(0) = 100
startPoint(1) = 100
startPoint(2) = 0
endPoint(0) = 200
endPoint(1) = 200
endPoint(2) = 0
Set lineObj = app.Documents(0).ModelSpace.AddLine(startPoint, endPoint)
End Sub

ADO recordset seems to cache old results

I am having an issue where I create a connection string (Excel) and query a worksheet, I can get the results, placed into a recordset, and then transposted into a destination worksheet.
The problem is that for some reason, if I go back and edit this worksheet (without saving), the recordset is caching the OLD results. eg: I first queried 10 rows, returned 10, deleted 7 of them, execute the query again but it returns the original 10 as opposed to my expectation for the remaining 3. I've used this method thoroughly and have never had this issue and believe it to be memory related somehow...
Please help...
Public Sub sbTest()
Dim wb As Workbook
Dim wsData As Worksheet, _
wsTmp As Worksheet
Set wb = ThisWorkbook
Set wsData = wb.Sheets("Data"): wsData.Cells.ClearContents
Set wsTmp = wb.Sheets("Temporary")
sSQL = "SELECT * FROM [" & wsTmp.Name & "$]"
Call mUtilities.sbRunSQL(sConnXlsm, wb.FullName, sSQL, wsData.Cells(1, 1))
'Cleanup
Set wb = Nothing
Set wsData = Nothing
Set wsTmp = Nothing
End Sub
Public Const sConnXlsm As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=zzzzz;Extended Properties=""Excel 12.0 Macro;HDR=YES;IMEX=1"";"
Public Sub sbRunSQL(ByVal sConn As String, ByVal sSource As String, ByVal sSQL As String, ByVal rDest As Range, _
Optional ByVal bHeader As Boolean = True, Optional ByVal bMsg As Boolean = True)
Dim oCn As ADODB.Connection, _
oRs As ADODB.Recordset, _
oFld As ADODB.Field
Dim vArr As Variant
'Setup
On Error GoTo Cleanup
'Handle DELETE and INSERT INTO Access queries seperately from other types
If (UCase(Left(sSQL, 6)) = "DELETE" Or UCase(Left(sSQL, 11)) = "INSERT INTO") And sConn = sConnAccess Then
Set oCn = CreateObject("ADODB.Connection")
oCn.Open Replace(sConn, "zzzzz", sSource)
sSQL = Replace(sSQL, "FROM ", "FROM [Excel 8.0;HDR=YES;DATABASE=" & ThisWorkbook.FullName & "].")
oCn.Execute sSQL
'Exit if successful
oCn.Close
Set oCn = Nothing
Exit Sub
Else
Set oRs = Nothing
Set oRs = New ADODB.Recordset
oRs.Open sSQL, Replace(sConn, "zzzzz", sSource), adOpenForwardOnly, adLockReadOnly
If Not (oRs.BOF And oRs.EOF) Then
vArr = oRs.GetRows
vArr = fTranspose(vArr) 'The .GetRows process tranposes the data so we need to undo this
If bHeader = True Then
For i = 0 To oRs.Fields.Count - 1
rDest.Offset(0, i).Value = oRs.Fields(i).Name
Next i
Range(rDest.Offset(1, 0), rDest.Offset(UBound(vArr, 1) + 1, UBound(vArr, 2))) = vArr
Else
Range(rDest, rDest.Offset(UBound(vArr, 1), UBound(vArr, 2))) = vArr
End If
'Exit if successful
oRs.Close
Set oRs = Nothing
Exit Sub
End If
End If
'Cleanup
Cleanup:
If bMsg = True Then
MsgBox "Critical error!" & vbNewLine & vbNewLine & _
"Error: " & Err.Description & vbNewLine & vbNewLine & _
"SQL: " & sSQL, vbCritical + vbOKOnly
End If
Set oCn = Nothing
Set oRs = Nothing
End Sub
For what it's worth, I was able to solve this and the issue seems to be related to some kind of latency bug if multiple instances of Excel are open. I've simply forced only one book to be open in such cases.
Set oWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set oProc = oWMI.ExecQuery("SELECT * FROM Win32_Process WHERE NAME = 'Excel.exe'")
If oProc.Count > 1 Then
MsgBox "There are " & oProc.Count & " instances of Excel open." & vbNewLine & vbNewLine & _
"Only 1 instance is allowed open in order to update database.", vbCritical + vbOKOnly
GoTo Cleanup
End If

COUNTIFS VLOOKUP returns a value?

I'm stuck for a formula. Essentially what i want to do is count the number of times a particular value appears in one sheet, based on data pulled from another sheet.
E.g. I have three sheets. One sheet has a list of jobs and a code associated with a client. The second sheet has a list of the clients and details on the client. The third sheet is my results sheet.
I want to count the How Heards for each company. Eg, in sheet 1 below Apple has 3 customers. If we use the Client Code Id's and go to Sheet 2, we can see that it will total 2 Online and 0 Facebook. This result displays on Sheet 3. The results sheet.
Sheet 1 Example
Sheet 2 Example
Sheet 3 Example (What i want the results to look like from calculation)
In the interest of actually providing a suitable answer to this question, here is some VBA code that allows a workbook to create an ADO connection to itself and generate a report using SELECT, DISTINCT, WHERE, INNER JOIN, GROUP BY and ORDER BY clauses.
Sub Inner_Join()
Dim cnx As Object, rs As Object
Dim sWS1 As String, sWS2 As String, sWB As String, sCNX As String, sSQL As String
Dim ws1TBLaddr As String, ws2TBLaddr As String
'Collect some string literals that will be used to build SQL
ws1TBLaddr = Worksheets("Sheet1").Cells(1, 1).CurrentRegion.Address(0, 0)
sWS1 = Worksheets("Sheet1").Name
ws2TBLaddr = Worksheets("Sheet2").Cells(1, 1).CurrentRegion.Address(0, 0)
sWS2 = Worksheets("Sheet2").Name
sWB = ThisWorkbook.FullName
'Build the connection string
'The first is for 64-bit Office; the second is more universal
sCNX = "Provider=Microsoft.Jet.OLEDB.12.0;Data Source=" & sWB _
& ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"";"
sCNX = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & sWB _
& ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"";"
'Debug.Print sCNX
'Create the necessary ADO objects
Set cnx = CreateObject("ADODB.Connection") 'late binding; for early binding add
Set rs = CreateObject("ADODB.Recordset") 'Microsoft AxtiveX Data Objects 6.1 library
'Open the connection to itself
cnx.Open sCNX
With Worksheets("Sheet3")
'Clear the reporting area
.Cells(1, 1).CurrentRegion.ClearContents
'get [Business Name] list from Sheet1
sSQL = "SELECT DISTINCT w1.[Business Name]"
sSQL = sSQL & " FROM [" & sWS1 & "$" & ws1TBLaddr & "] w1"
sSQL = sSQL & " ORDER BY w1.[Business Name]"
'Debug.Print sSQL
'Populate Sheet3!A:A
rs.Open sSQL, cnx
Do While Not rs.EOF
'Debug.Print rs.Fields("Business Name")
.Cells(.Rows.Count, 1).End(xlUp).Offset(1, 0) = rs.Fields("Business Name")
rs.MoveNext
Loop
rs.Close
'get [How Heard] list from Sheet2
sSQL = "SELECT DISTINCT w2.[How Heard]"
sSQL = sSQL & " FROM [" & sWS2 & "$" & ws2TBLaddr & "] w2"
sSQL = sSQL & " WHERE w2.[How Heard] NOT LIKE 'None'"
sSQL = sSQL & " ORDER BY w2.[How Heard]"
'Debug.Print sSQL
'Populate Sheet3!1:1
rs.Open sSQL, cnx
Do While Not rs.EOF
'Debug.Print rs.Fields("How Heard")
.Cells(1, .Columns.Count).End(xlToLeft).Offset(0, 1) = rs.Fields("How Heard")
rs.MoveNext
Loop
rs.Close
'start by seeding zeroes for all
With .Cells(1, 1).CurrentRegion
With .Resize(.Rows.Count - 1, .Columns.Count - 1).Offset(1, 1)
.Cells = 0
End With
End With
'get the counts for the [Business Name]×[How Heard] combinations
sSQL = "SELECT COUNT(w1.[Business Name]), w1.[Business Name], w2.[How Heard]"
sSQL = sSQL & " FROM [" & sWS1 & "$" & ws1TBLaddr & "] w1"
sSQL = sSQL & " INNER JOIN [" & sWS2 & "$" & ws2TBLaddr & "] w2 ON w1.[Client Code] = w2.[Client Code]"
sSQL = sSQL & " WHERE w2.[How Heard] <> 'None'"
sSQL = sSQL & " GROUP BY w1.[Business Name], w2.[How Heard]"
'Debug.Print sSQL
'Populate Sheet3 data matrix area
rs.Open sSQL, cnx
With .Cells(1, 1).CurrentRegion
Do While Not rs.EOF
'Debug.Print rs.Fields(0) & ":" & rs.Fields(1) & ":" & rs.Fields(2)
.Cells(Application.Match(rs.Fields(1), .Columns(1), 0), _
Application.Match(rs.Fields(2), .Rows(1), 0)) = rs.Fields(0)
rs.MoveNext
Loop
End With
rs.Close
End With
Final_Cleanup:
Set rs = Nothing
cnx.Close: Set cnx = Nothing
End Sub
Results should be similar to the following.
    
Ok, so I am really impressed with the answer by #Jeeped
My answer is not as flexible as being able to use arbitrary SQL but it doesn't use VBA so it might be useful as well in some contexts.
So my answer basically:
creates an array from Sheet1 that contains the client code for each matching cell(or 0 for non matching cells)
X = ((Sheet1!$B$2:$B$1000=$A2)*Sheet1!$A$2:$A$1000)
creates an array from Sheet2 that contains the client code for each matching cell(or 0 for non matching cells)
Y = ((Sheet2!$B$2:$B$2000=B$1)*Sheet2!$A$2:$A$2000)
compares every cell in the two arrays where the value of the first array isn't 0
Z = (X<>0)*(X=TRANSPOSE(Y))
and then sums up the number of matches:
=SUM(Z)
So the final formula for Sheet3!B2 is:
=SUM((((Sheet1!$B$2:$B$1000=$A2)*Sheet1!$A$2:$A$1000)<>0)*(((Sheet1!$B$2:$B$1000=$A2)*Sheet1!$A$2:$A$1000)=TRANSPOSE(((Sheet2!$B$2:$B$2000=B$1)*Sheet2!$A$2:$A$2000))))
It is an array formula so you need to press Control-Shift-Enter instead of just Enter. Then you need to copy it from B2 to C2, B3 and so on.
Obviously, You will have to change the 1000 to something bigger than the largest rwo on Sheet1 and the 2000 to something bigger than the largest row on Sheet2.

Resources