Updating column values on specific Row using VBA - excel

How to update value from xt to xtt in 6th column, first row.
1 2 3 4 5 6
x xx xy xz x1 xt
y yx tt cc z3 xcc
Based on above data, I am getting range from worksheet. After getting the Row object, how do I update the Cell value in particular column?

As asked, you can update a specific column using the method:
'Sheet.Cells(row, column) = value
' i.e.
ActiveSheet.Cells(1, 6) = "xtt"
If you only want to perform the update if it has a value of "xt", then obviously you'd need to check the contents before performing the update... For example:
If (ActiveSheet.Cells(1, 6) = "xt") Then
ActiveSheet.Cells(1, 6) = "xtt"
End If

Related

Excel - two columns - remove duplicate values buy comparing pairs in rows

I'm using Excel 2013, simplifying the actual data, suppose you have two columns of data, similar to below:
Column1
Column2
A
D
A
C
B
C
C
B
C
A
D
A
My goal is to either filter or remove the duplicate pairs regardless of what column they're in. My desired output would be as follows:
Column1
Column2
A
D
A
C
B
C
So, as you can see, the C-B row was eliminated because the pair exists in the row containing B-C. Same for the rows containing C-A (A-C) and D-A (A-D). Data will be in no particular order and it doesn't matter which of the two paired matches are removed.
Solution can be via creating a new table or even using VBA to output a new table. Whatever is easiest.
Thanks in advance!
I was able get this to work for me, so I thought I'd post my answer hopefully helping someone else. As I suspected, and Quailia suggested, VBA was the way to go.
Few things changed along the way. I needed to add an additional column to the table as it was determined that there would be some duplicates that I needed to keep. The values in the first column now group rows together, so later duplicates are kept. The values I need to check for duplicate pairs, are in column 2 and 3.
Table1:
Column1
Column2
Column3
01
A
D
01
A
C
01
B
C
01
C
B
01
C
A
01
D
A
Also, I realized I would be dealing with a fixed number of rows, so I didn't have a need to keep changing the size of my array.
Sub RemoveDuplicatePairs()
'Checks a 3 column table for rows with duplicate values when column 2 and 3 are swapped, removes duplicates and outputs unique rows to a new table
Dim aArrayList() As Variant
Dim bArrayList(1 To 144, 1 To 3) As Variant
Dim aRowNum As Integer, aColNum As Integer, bRowNum As Integer, bColNum As Integer
aArrayList = Range("Table1")
bRowNum = 1
'Loop through rows of 1st array
For aRowNum = 1 To UBound(aArrayList, 1)
If aRowNum = 1 Then
bArrayList(1, 1) = aArrayList(1, 1)
bArrayList(1, 2) = aArrayList(1, 2)
bArrayList(1, 3) = aArrayList(1, 3)
'Debug.Print bArrayList(bRowNum, 1) & aArrayList(bRowNum, 2) & bArrayList(aRowNum, 3)
bRowNum = 2
ElseIf aRowNum > 1 Then
'Check if current row in 1st array already exists in 2nd array by comparing values after flipping 2nd and 3rd column values from 1st array
For i = 1 To bRowNum - 1
If aArrayList(aRowNum, 1) = bArrayList(i, 1) And aArrayList(aRowNum, 2) = bArrayList(i, 3) And aArrayList(aRowNum, 3) = bArrayList(i, 2) Then
'Duplicate pair already exists, move onto next row of 1st array
GoTo SKIP
End If
Next i
'No duplicate found, add row from 1st array to 2nd array
bArrayList(bRowNum, 1) = aArrayList(aRowNum, 1)
bArrayList(bRowNum, 2) = aArrayList(aRowNum, 2)
bArrayList(bRowNum, 3) = aArrayList(aRowNum, 3)
'Debug.Print bArrayList(bRowNum, 1) & bArrayList(bRowNum, 2) & bArrayList(bRowNum, 3)
bRowNum = bRowNum + 1
SKIP:
End If
Next aRowNum
'Write array to new table
Sheets("Sheet1").Range("Table2").Value = bArrayList()
End Sub
Table2:
Column1
Column2
Column3
01
A
D
01
A
C
01
B
C
I'm sure there is an easier, neater way to do the same thing, but as my username implies, I'm still pretty new to this. Any suggestions that improve or simplify my logic are certainly welcome.

Transpose columns into new column and maintain/duplicate rows accordingly

Apologies for awkward title. I have searched through the forums but not yet come across a solution which is appropriate. I imagine what I am after will require the use of a macro.
I have a spreadsheet which outlines transactions by row, that is, one row for each transaction. Each transaction contains projected financial data. So, each row relates to one transaction which has financial impacts across multiple years.
For example, the header looks like
Transaction | field1 | field 2 | etc. | 2010-11 | 2011-12 | 2012-13 | etc. |
Beneath the years are dollar amounts.
All the fields contain data I need replicated across rows, except I want the year transposed into a single column, with the financials against it.
So if I have the record:
exampleid | data | data | 45000 | 56000 | 223145 | data
I would like it too become:
exampleid | data | data | 2010/11 | 45000 | data
exampleid | data | data | 2011/12 | 56000 | data
exampleid | data | data | 2012/13 | 223145 | data
There are around 30 columns.
You don't need VBA. You can use/adapt the formulas posted here.
That post was intended precisely as a reference for cases like this one.
For each of your input rows, you need two sets of formulas row-to-column, one for the headers and one for the data.
Use appropriate relative/absolute indexes in formulas, to be able to copy/paste.
Here's what I use to do this. You can change the variables at the start of the sub to dictate how many columns you have with data, how wide your pivoted data is, which sheet names are used for the import and the export, etc etc.
The exported data will always start at the same column that the original data started at.
The data needs to have headers to work correctly, and it assumes there are no blank cells in the first column of data.
Sub pivot_data()
data_sheet = "Sheet1" 'name of sheet containing original data
export_sheet = "Sheet2" 'name of sheet to export to
start_d_row = 2 'first row of data (headings are grabbed from row above)
start_d_col = 1 'first column of data
end_d_col = 7 'last column of data
start_t_col = 4 'first column to pivot
end_t_col = 6 'last column to pivot
xrow = 2 'first row to export DATA to (headings will be row above)
trailing_col = end_d_col - end_t_col 'calculated number of trailing columns
pivot_size = end_t_col - start_t_col + 1 'calculated size of pivot
'headings
For xcol = start_d_col To start_t_col - 1
Worksheets(export_sheet).Cells(xrow - 1, xcol).Formula = Worksheets(data_sheet).Cells(start_d_row - 1, xcol).Value
Next xcol
Worksheets(export_sheet).Cells(xrow - 1, xcol).Formula = "Narrative"
Worksheets(export_sheet).Cells(xrow - 1, xcol + 1).Formula = "Value"
For xcol = start_t_col + 2 To start_t_col + 2 + trailing_col - 1
Worksheets(export_sheet).Cells(xrow - 1, xcol).Formula = Worksheets(data_sheet).Cells(start_d_row - 1, xcol - 2 + pivot_size).Value
Next xcol
'data
For irow = 2 To Worksheets(data_sheet).Cells(start_d_row - 1, start_d_col).End(xlDown).Row
For icol = start_t_col To end_t_col
For xcol = start_d_col To start_t_col - 1
Worksheets(export_sheet).Cells(xrow, xcol).Formula = Worksheets(data_sheet).Cells(irow, xcol).Value
Next xcol
Worksheets(export_sheet).Cells(xrow, start_t_col).Formula = Worksheets(data_sheet).Cells(1, icol).Value
Worksheets(export_sheet).Cells(xrow, start_t_col + 1).Formula = Worksheets(data_sheet).Cells(irow, icol).Value
If end_d_col = end_t_col Then
Else
For xcol = start_t_col + 2 To start_t_col + 2 + trailing_col - 1
Worksheets(export_sheet).Cells(xrow, xcol).Formula = Worksheets(data_sheet).Cells(irow, xcol - 2 + pivot_size).Value
Next xcol
End If
xrow = xrow + 1
Next icol
Next irow
End Sub
Hope that helps
VBA can certainly be used to solve this problem but for regularly structured data such as this native Excel alone can also be used.
The basic problem is that you want to split each record in your "input" list into n records in your "output" list. So if you have i records in your input list you will have i*n records in the output.
I used to do a lot this sort of stuff on the UK Office for National Statistics population data, where the data was published in neatly formatted tables showing population levels by age group and location whereas I wanted it in a list format with each record showing just the population in a single location and age group combination. The list format was often then used either with Excel's data filtering and/or Pivot tables for analysis purposes and occasionally imported into Access.
The approach to transforming the data is as follows.
Assuming for example you have 25 years worth of data in your input table and say 200 input records, you want to generate 200*25=5000 output records so first generate a 2 column list of with 5000 rows. Start with 1,1 in the 1st row; 1,2 in 2nd row; 1,3 in 3rd row; ... ;1,25 in 25th row; 2,1 in 26th row; 2,2 in 27th row; ... ; 2,25 in 50th row; 3,1 in 51st row; and so on until you reach 200,25 in the 5000th row. Such a list is easy enough to generate: assuming cells A2 and B2
represent the first 1,1 (simply type these values into the two cells) then B3 has a formula such as
IF(B2=25,1,1+B2) which can be copied down the remaining rows of
column B. A3 also contains a formula based on the IF function, but this time
the first argument is based on the value in the adjacent cell (ie B3). The precise formula is left as an exercise and, again should be copied down the remaining rows of column A.
The 5000 rows correspond to your output records and each pair of values tells you which input record (first value) and which year within that record (second value) provides the data for the output record. You now have a choice of functions for using this information to create cells containing the output records. Possibilities include the INDEX(), OFFSET() and INDIRECT() functions though the latter will need to be used in conjunction with the ADDRESS() function.
INDEX() is probably most straightforward to understand and apply but the others are worth exploring and understanding. If your 200 input records, not including the header row, is held in say Sheet1!A2:AB201 (with cols A-C used for the non-year data and the 25 years of yearly data being in columns D-AB) and the output table is to appear on Sheet2 (with row 1 being a header row and columns A and B being used as described in step 1., above) then the formula for Sheet2!C2 would be =INDEX(Sheet1!A$2:A$201,$A2) and this formula can be copied both for all output rows and the next 2 (non-year) output columns (note the use of mixed absolute and relative addressing that achieves this). The year value for the 4th column of the output list (column F) is generated by picking out the correct value from the header row in Sheet1. The formula to use is =INDEX(Sheet1!$D$1:$AB$1,B2) in cell Sheet2!F2. Copy this formula down the remaining rows of column F. The formula for cell Sheet2!G2 uses the two dimensional version of the =INDEX() function - but I'll leave that one as an exercise. Once you've got the correct formula it should be copied down the remaining rows of column G.
If you have navigated the above successfully your output data should be in Sheet2!C2:G5001 and you can type your column headers into row 1.
One final comment on your terminology. You are not transposing your data, instead you are transforming the way it is presented. Transposing data usually means converting all the rows of a table into columns and vice-versa: so a table with I rows and J columns is transposed to become a table with J rows and I columns. In your case, the dollar values are transformed from I rows and J columns to I*J rows and 1 column.

Excel - Entries in List of values be based on some other column value

We have a scenario in excel (2010) where the list of values present in a dropdown change dynamically based on some column of that row. For eg. Consider the "Supervisor" dropdown in sheet1 below:
Emp Grade Supervisor
A 14
B 12
C 13
D 12
E 12
F 13
G 14
Now let's say there is a dropdown for the supervisor. For every employee, the supervisor can be a person of his grade or higher grades only. So, for eg. For grade 13 employee, can have a supervisor with grade 13 or grade 14 only, not grade 12.
How can I write a custom condition like this inside the list of values? I have tried with things like named range, offset etc. but none allows specifying custom conditions. Any help?
I found the following document to be helpful in creating dependent Data Validation dropdowns: DV0064 - Dependent Lists Clear Cells, which can be downloaded here (for free):
http://www.contextures.com/excelfiles.html#DataVal
You can tailor the example to your needs.
=OFFSET('validation pivot'!$A$1,0,1,COUNTIFS('validation pivot'!$A:$A,">="&B2),1)
The supervisor needs to be at least his pay grade (>=B2). In order to have it work you need to have the pivot inserted in validation pivot A1. How to create the pivot (hasty notes):
add grade and emp 'emp as subset
tabular view 'to have separate columns
repeat labels ' to be able to count them
remove autosums(both within and total) 'to not deal with evading it
hide column labels and filters 'same
descending order(grade) 'to get a simple match method
data: store none 'to refresh the descending order every time
See uploaded sample file.
This code (column A = EMP, B = Grade, C = Supervisor)
Sub test()
Dim actualgrade As Integer
Dim lastRowA As Integer
Dim numbers As String
lastRowA = Sheets("sheet1").Cells(Sheets("sheet1").Rows.Count, "A").End(xlUp).Row
For i = 2 To lastRowA '1 = headers
actualgrade = Cells(i, 2)
For j = 2 To lastRowA
If Cells(j, 2) >= actualgrade Then
numbers = numbers & " " & Cells(j, 1).Value
End If
Next j
Cells(i, 3).Value = numbers
numbers = ""
Next i
End Sub
Makes this result:
Emp Grade Supr
A 14 A G
B 12 A B C D R F G
C 13 A C F G
D 12 A B C D R F G
R 12 A B C D R F G
F 13 A C F G
G 14 A G
Feel free to change it like you need it

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 ..

Is it possible to add/subtract in one cell, and have it subtract/add in another cell that already has a value?

Is it possible to add/subtract in one cell, and have it subtract/add in another cell that already has a value?
I am thinking it may be a if function but I can not wrap my head around how I would write out the formula.
Let's say you have 2 columns B and C that already contain data.
And if you Add a number to B you want that number to be subtracted from C.
My recommendation is to write a macro that will work as follows:
First the user selects the two columns and then runs the macro
For each row
Cell c = getCell("C" + row);
double cval = c.Value;
c.type = FORMULA;
c.Formula = "=" + (cval + getCell("B" + row).Value) + "-B"+row;
c.Recalculate()
Example:
Original:
A B C
1 Gas 5 10
2 Air 8 12
Replace with:
A B C
1 Gas 5 =15-B1
2 Air 8 =20-B2
so you only change B, and the value of C is automatically calculated.

Resources