Cannot make .Offset to work in excel vba macro - excel

I am stuck, and would like a little hlep. I'm trying to get a qty on Column D12, d14, d16 .... to d42. Than multiply this qty by a value. the value sheet look like this.
Value Sheet
A B C
ItemName Quality Confort
1 Chair 2 1
2 Bed 0 3
3 Table 1 1
Quantity Sheet
A B C D
ItemName QTYColumn
12 .. Table 2
13
14 .. Chair 5
15
16 .. Bed 6
Total Sheet
A B
Quality 12 (2*1 + 5*2 + 6*0 )
Confort 25 (2*1 + 5*1 + 6*3 )
I'm pretty sur I have the hardest part done. I can check and grab the quantity from all the sheets I want. I also got a function done where you pass the name of the item, and the stats name, and it return me the results I want.
so, I got this part of the code atm which doesnt work, and its driving me nuts.
For Counter = 12 To 42 Step 2
For Each qColumn In QTYColumn
Set QTY = Range(qColumn & Counter)
Dim ItemName As Range
ItemName= QTY.Offset(-2, 0).Select
total = total + (QTY * GetValue(ItemName, "Confort"))
Next qColumn
Next Counter
My problem is with the ItemName variable. Its always empty and as soon as I get to it with the debugger, the function stops and it closes. Anyone have any idea as to why ? it's important for me to get it base on the offset -2 and not the column adress because it might be different depending of the sheet, and the only "sure" way to find it is the get the 2nd cell to the left of the quantity cell.

ItemName= QTY.Offset(-2, 0).Select does not mean anything !
Either you Select:
QTY.Offset(-2, 0).Select
or you get the value:
ItemName= QTY.Offset(-2, 0).Value '(value can be omitted here)
But then, Dim ItemName As Range does not make sense. It should be a String or a a number.
or you get the range:
Set ItemName= QTY.Offset(-2, 0) ' then you need Set

Related

Counting number of instances according to date difference (Excel/VBA)

I have the following data:
Excel Table Screen Capture
That is:
Acquirer ID ||| Target ID (not useful) ||| Date
123 ||| 456 ||| 20/01/2020
789 ||| 910 ||| 28/02/2019
I would like an additional column where for each acquirer I have a count of how many acquisitions it made in the past 3 years.
Therefore, for each acquirer ID with a given date, I need to count how many times that ID appears with a date less than 3 years distant from that date.
Thus if an acquirer made an acquisition in 2020, 2016, 2015 and 2014, in each instance, the count will amount to 0, 2, 1, 0 respectively for that given acquirer.
I have tried with COUNTIFS(), IF (), VLOOKUP(), but I could not get the result wanted as, once the condition is met, it sums all the IDs irrespective of the dates.
I also tried writing a Macro on VBA but my knowledge of the language is basically 0. I post the code in case it gives a better idea of the problem
Dim Sheet As Worksheet
Set dbs = ThisWorkbook.Sheets("db")
Dim i As Integer, j As Integer, count As Integer
lr = dbs.Cells(Rows.count, 1).End(xlUp).Row
x = 0
For i = 2 To lr
For j = i + 1 To lr
Set myrange = Range("i:lr")
If dbs.Cells(i, 4).Value - Application.WorksheetFunction.VLookup(dbs.Cells(i, 4).Value, myrange, 4, False) < 3 Then
'I get a bug with Application.WorksheetFunction.VLookup, it might be that an error must be dealt with in case of missing values
count = count + 1
End If
Next j
Next i
dbs.Cells(i, 5).Value = count
End Sub
Any help is really appreciated, thank you in advance.
For Acquirer in A2:A10 and Dates in C2:C10, this formula goes in D2 and counts the number of records where all of the following are true:
Acquirer ID is the same as A2
Date is less than the date in C2
Date is greater than or equal to 3 years before the date in C2
=COUNTIFS($A$2:$A$10,A2,$C$2:$C$10,"<"&C2,$C$2:$C$10,">="&EDATE(C2,-36))

Assign values in large scale into a data base. Formula (libreOffice calc)

I am trying to create a data base in libreOffice spreed-sheet application. And what I need is, the first column to be Id's, but each Id has to fill 100 cells. So I would like to have 2000 Id's and each Id takes up 100 cells, we have 200 000 cells. (Id's values = range(1,2000))
row#1 : row#100 = Id#1 // row#101 : row#200 = Id#2 ....// row#199900 : row#200000 = Id#2000
What I simply want is to assign the value 1 to the first 100 cells in the first column, the value 2 to the next 100 cells in the same column and so on, until I have the 2000 Id's in the first column.
So I would like to find a formula to achieve that with out having to select and scroll manually 2000 times the sheet.
Thanks
If the ID is in A column:
=QUOTIENT(ROW(A1);100)+1
The formula adds 1 to integer part of the number of row divided by 100.
Apply with a loop?
Public Sub test()
Dim i As Long
For i = 1 To 2000
Range("A1:A100").Offset((i - 1) * 100, 0) = i
Next
End Sub

Create new Excel rows based on column Heading and populate the data

I have to create output XLS file based on input xls file header. I am giving below exact requirement. hope its clear. if not then please let me know.
Iput XLS -->
ID Version NameLegacy ProjectNumber OwnerName Language Keywords OwnerSite External Content Relevance Periodic Coremap ValidTo
1 1 Mohan 1000 x ENG ABCD AB No ok no 5 2017-10-14 2018-10-14
2 2 Shayam 1001 y ENG EFGH BC No ok yes 2 2017-10-14 2018-10-14
3 1 Sourabh 1002 z ENG IJKL CD Yes no no 4 2017-10-14 2018-10-14
Based on this Input XLS File, i need Output XLS File as below. Each row of input file will have 12 row of output file and respective value will be filled in Output file from input file.
ID Version IBANAME STRINGVALUE INTEGERVALUE FLOATVALUE FLOATVALUEWITHUNITS BOOLVALUE TIMEVALUE URLVALUE REFERENCEVALUE
1 1 NameLegacy Mohan
1 1 ProjectNumber 1000
1 1 OwnerName x
1 1 Language ENG
1 1 Keywords ABCD
1 1 OwnerSite AB
1 1 External No
1 1 Content ok
1 1 Relevance no
1 1 Periodic 5
1 1 Coremap 2017-10-14
1 1 ValidTo 2018-10-14
2 2 NameLegacy Shayam
2 2 ProjectNumber 1001
2 2 OwnerName y
2 2 Language ENG
2 2 Keywords EFGH
2 2 OwnerSite BC
2 2 External No
2 2 Content ok
2 2 Relevance yes
2 2 Periodic 2
2 2 Coremap 2017-10-14
2 2 ValidTo 2018-10-14
3 1 NameLegacy Sourabh
3 1 ProjectNumber 1002
3 1 OwnerName z
3 1 Language ENG
3 1 Keywords IJKL
3 1 OwnerSite CD
3 1 External Yes
3 1 Content no
3 1 Relevance no
3 1 Periodic 4
3 1 Coremap 2017-10-14
3 1 ValidTo 2018-10-14
Thanks in advance.
There are a few steps to do this using VBA. The main purpose is to identify what you are actually trying to do.
It seems like you are attempting to sort through records to identify what the format of the information is and place it in a column designated for only that format. To do this, I have created a very simple custom Function..
This function takes in the name of the header as a string, and uses Select/Case to find appropriate matches for which column the target sheet needs. This is custom to your specific layout. Feel free to adapt or change it.
FUNCTION TO FIND CORRECT COLUMN ON TARGET
Function ColFinder(header As String) As Long
'Target Column Format = Column #
'"STRINGVALUE" = 4
'"INTEGERVALUE" = 5
'"FLOATVALUE" = 6
'"FLOATVALUEWITHUNITS"= 7
'"BOOLVALUE" = 8
'"TIMEVALUE" = 9
'"URLVALUE" = 10
'"REFERENCEVALUE" = 11
' **** SET VALUES FOR CASES TO MATCH DESIRED FORMAT ABOVE ****
'Default to Column 4 StringValue if unknown
Select Case header
Case "NameLegacy"
ColFinder = 4
Case "ProjectNumber"
ColFinder = 5
Case "OwnerName"
ColFinder = 4
Case "Language"
ColFinder = 4
Case "Keywords"
ColFinder = 4
Case "OwnerSite"
ColFinder = 10
Case "External"
ColFinder = 8
Case "Content"
ColFinder = 11
Case "Relevance"
ColFinder = 8
Case "Periodic"
ColFinder = 5
Case "Coremap"
ColFinder = 9
Case "ValidTo"
ColFinder = 9
End Select
End Function
Using a few other Functions for finding Last Row & Last Column
Last Row Function
Function lastRow(sheet As String) As Long
lastRow = Sheets(sheet).Cells(Rows.Count, "A").End(xlUp).Row 'Using Cells()
End Function
Last Column Function
Function lastCol(sheet As String) As Long
lastCol = Sheets(sheet).Cells(1, Columns.Count).End(xlToLeft).Column
End Function
With these three functions, you can run a simple loop through the source sheet, one row at a time, then look to see which column the data is coming from, and place it on the appropriate target.
This example is using two worksheets in the same workbook. To change, just extend the address to include other workbooks or sheets. This is just the simplest way to show the concept.
CODE TO LOOP THROUGH SHEETS
Sub ColsToRows()
Dim tRow As Long, sCol As Long, sRow As Long
Dim source As String, target As String
Dim tString As String
source = "Sheet1"
target = "Sheet2"
'Set target Row starting point
tRow = 2
'Loop through Source Rows with Data, starting after Header Row
For sRow = 2 To lastRow(source)
'Loop through each header in Source Row
For sCol = 3 To lastCol(source)
'Set Basic Columns on Target
Sheets(target).Cells(tRow, 1) = Sheets(source).Cells(sRow, 1)
Sheets(target).Cells(tRow, 2) = Sheets(source).Cells(sRow, 2)
'Get Header Name as Temp String to find which format it requires
tString = Sheets(source).Cells(1, sCol)
'Label Column 3 of Target
Sheets(target).Cells(tRow, 3) = Sheets(source).Cells(1, sCol)
'Find Appropriate Column using custom Formula [ColFinder(header As String) As Long]
Sheets(target).Cells(tRow, ColFinder(tString)) = Sheets(source).Cells(sRow, sCol)
'Advance to next Target Row
tRow = tRow + 1
Next sCol
Next sRow
End Sub
Source Sheet Example
Target Sheet Example
You can convert the upper table to the lower one using formulas within Excel.
We start from defining all the input range, without the first 2 columns and the headers row as a range named input. This is done by selecting all the range and typing "input" in the "Name box":
Create the following table where you like in the workbook, then define it all and a range named col_index:
STRINGVALUE INTEGERVALUE FLOATVALUE FLOATVALUEWITHUNITS BOOLVALUE TIMEVALUE URLVALUE REFERENCEVALUE
NameLegacy ProjectNumber External Coremap OwnerSite Content
OwnerName Periodic Relevance ValidTo
Language
Keywords
This table basically sorts the original columns into their new place. You can add values, rows or columns to the table and it will stay intact, as long as you keep all of it under the name range col_index.
Then create another table headers:
ID Version IBANAME STRINGVALUE INTEGERVALUE FLOATVALUE FLOATVALUEWITHUNITS BOOLVALUE TIMEVALUE URLVALUE REFERENCEVALUE
Now paste the following formulas in the first row in each of column 1-4:
ID: =IF(C2=sheet1!$C$1,A1+1,A1)
Version: =VLOOKUP(A2,sheet1!$A$1:$B$4,2)
after selecting the first 12 rows under IBANAME, press F2, and paste: =TRANSPOSE(sheet1!C1:N1) as array formula! (press ctrl+shift+enter after pasting to the formula box)
STRINGVALUE: =IF(ISERROR(MATCH($C16,OFFSET(col_index,0,MATCH(D$15,OFFSET(col_index,0,0,1,11),0)-1,5,1),0)-1),"",OFFSET(input,TRUNC((ROW()-ROW($D$16))/COLUMNS(input)),MOD(ROW()-ROW($D$16),COLUMNS(input)),1,1))
Next, drag columns ID and Version 12 rows down, to the next ID (row 14), then change the value in cell A2 to 1, and the value in C14 to =C2, and continue dragging columns ID, Version and IBANAME until the end of the data is reached. Finally, drag the cell D2 left to the end of the row, and then down to fill all the table.
This it how it looks with formulas:
And this is with values:
That's it ;)

Spreadsheet/Excel array functions that compare and validate values

I got this dataset
ID fruit price
1 apple 10
2 apple 50
3 apple 100
4 banana 10
5 banana 20
6 banana 50
and would like a (set of) forumla(s) that go through the rows and output the row for each fruit that has the highest price.
In e.g. PHP I would do something like this
foreach $array as $row{
if in_array( $row[fruit] ){
/* check if current $row[price] for current $row[fruit] is larger than existing post. If yes replace */
}
}
How would I do that in Google Spreadsheets / Excel?
You can do it in Excel with array formulas (so you enter it with Ctrl+Shift+Enter)...
If your fruit is in B and price in C your array formula in D2 would be
=C2=MAX(IF($B$2:$B$7=B2,$C$2:$C$7,0))
This will give you TRUE or FALSE for whether that row has the highest price for that fruit.
It works by doing an IF on the array of fruits (rows 2 to 7 - you can make it longer) being the same as the current fruit - if it is the same, return the price, otherwise 0. We then get the MAX and compare it to the current row's price.
Good luck!
I've put together a quick VBA macro that you could use in excel that will output the fruit with the highest price.
The macro converts the table of fruit toa an array and then loops through the array to find the fruit with the highest value, before outputting it to the sheet. This macro relies on the table of fruit being positioned in columns A to C.
Sub getMaxPriceFruit()
'put data table into an array
Dim dataTableArray() As Variant
dataTableArray = Range("A2:C" & Cells(Rows.Count, "A").End(xlUp).Row)
'loop through the aray looking for the largest value
'capture array index in variable when largest is found
Dim maxArray(1 To 1, 1 To 3) As Variant
maxArray(1, 1) = 0
maxArray(1, 2) = ""
maxArray(1, 3) = 0
Dim i As Long
For i = 1 To UBound(dataTableArray)
If dataTableArray(i, 3) > maxArray(1, 3) Then
maxArray(1, 1) = dataTableArray(i, 1)
maxArray(1, 2) = dataTableArray(i, 2)
maxArray(1, 3) = dataTableArray(i, 3)
End If
Next i
'output the fruit with the max value
Range("F2").Value = maxArray(1, 1)
Range("G2").Value = maxArray(1, 2)
Range("H2").Value = maxArray(1, 3)
End Sub
The limitation of this script is that if there are two fruit with an equal max value, the first fruit in the list with that value will be selected as the winner. If you would like the additional code to output multiple fruits if they have the same max value I can provide, but put simply you could utilise the maxArray array to capture all of the top ranking fruits and then loop through this array to output them all in one go.
Hope that helps!
A pivot table with fruit for Rows and price for Values (Summarise by: MAX) may serve.

Auto calculate average over varying number values row by row

I have an Excel file with several columns in it and many rows. One column, say A has ID numbers. Another column, say G has prices. Column A has repeating ID numbers, however not all numbers repeat the same amount of times. Sometimes just once, other times 2, 3 or several times. Each column G for that row has a unique price.
Basically, I need to average those prices for a given ID in column A. If each ID was repeated the same number of times, this would be quite simple, but because they are not I have to manually do my average calculation for each grouping. Since my spreadsheet has many many rows, this is taking forever.
Here is an example (column H is the average that I am currently calculating manually):
A ... G H
1 1234 3.00 3.50
2 1234 4.00
3 3456 2.25 3.98
4 3456 4.54
5 3456 5.15
11 8890 0.70 0.95
13 8890 1.20
...
So in the above example, the average price for ID# 1234 would be 3.50. Likewise, the average price for ID# 3456 would be 3.98 and for #8890 would be 0.95.
NOTICE how rows are missing between row 5 and 11, and row 12 is missing too? That is because they are filtered out for some other reason. I need to exclude those hidden rows from my calculations and only calculate the average for the rows visible.
Im trying to write a VBA script that will automatically calculate this, then print that average value for each ID in column H.
Here is some code I have considered:
Sub calcAvg()
Dim rng As Range
Set rng = Range("sheet1!A1:A200003")
For Each Val In rng
Count = 0
V = Val.Value '''V is set equal to the value within the range
If Val.Value = V Then
Sum = Sum + G.Value
V = rng.Offset(1, 0) '''go to next row
Count = Count + 1
Else
'''V = Val.Value '''set value in this cell equal to the value in the next cell down.
avg = Sum / Count
H = avg '''Column G gets the avg value.
End If
Next Val
End Sub
I know there are some problems with the above code. Im not too familiar with VBA. Also this would print the avg on the same line everytime. Im not sure how to iterate the entire row.
This seems overly complicated. Its a simple problem in theory, but the missing rows and differing number of ID# repetitions makes it more complex.
If this can be done in an Excel function, that would be even better.
Any thoughts or suggestions would be greatly appreciated. thanks.
If you can add another row to the top of your data (put column Headers in it) its quite simple with a formula.
Formula for C2 is
=IF(A2<>A1,AVERAGEIFS(B:B,A:A,A2),"")
copy this down for all data rows.
This applies for Excel 2007 or later. If using Excel 2003 or earlier, use AVERAGEIF instead, adjusting ranges accordingly
If you can't add a header row, change the first formula (cell C1) to
=AVERAGEIFS(B:B,A:A,A1)
In my way ..
Sub calcAvg()
Dim x, y, i, y2, t, Count, Mount As Integer
Dim Seek0 As String
x = 1 '--> means Col A
y = 1 '--> means start - Row 1
y2 = 7 '--> means end - Row 19
For i = y To y2
If i = y Then
Seek0 = Cells(i, x)
t = i
Count = Cells(i, x + 6)
Mount = 1
Else
If Cells(i, x) <> Seek0 Then
Cells(t, x + 7) = Count / Mount
Count = Cells(i, x + 6)
Mount = 1
t = i
Seek0 = Cells(i, x)
Else
Count = Count + Cells(i, x + 6)
Mount = Mount + 1
End If
End If
Next
End Sub
Hope this helps ..

Resources