I am after a dynamic macro that subtracts numbers in C2 onwards from B2 onwards and puts them in D2 onwards.
Numbers in C2 onwards are fixed, although the user will put numbers in B2 onwards. The length of Column C (Hours Charged) changes dependent on the sheet that has been imported. The code is as follows:
Dim O As Long
O = Cells(Rows.Count, "C").End(xlUp).Row
Cells(O + 1, "C").Formula = "=SUM(C2:C" & O & ")"
Cells(O + 1, "C").Interior.Color = RGB(208, 247, 197)
Cells(O + 1, "C").Font.Bold = True
The sheet looks something like this (the first column is B, the last is D):
Hours Budgeted | Hours Charged | Variance
0 | 85 | 0
0 | 31 | 0
0 | 20 | 0
0 | 100 | 0
0 | 75 | 0
To summarise, when a user inputs a value in the Hours Budgeted (B) column, i want it to automatically subtract from the Hours Charged (C) column and display in the Variance (D) column.
The reason why this can't just be a '=C2-B2' is because I have a macro inputting all this data, as well as a separate macro that 'Resets' the sheet (removing all data and formulas).
Thanks all,
Jake.
The following code should do the trick, just add it after the code you posted.
For i = 2 To O
Cells(i, "D").FormulaR1C1 = "=RC[-1]-RC[-2]"
Next i
FormulaR1C1 lets you insert cells references that are relative to the cell you're putting the formula into, so R[2]C[3] would insert a reference to a cell three rows down and three columns to the right.
I am looking for a way to copy each row in a sheet and paste it under the original row.
CURRENTLY:
1 | abc | def
2 | ghi | jkl
3 | mno | pqr
WHAT I AIM TO DO:
1 | abc | def
2 | abc | def
3 | ghi | jkl
4 | ghi | jkl
5 | mno | pqr
6 | mno | pqr
Hope this makes sense!
Here is one method which does not require fancy formulas or macros/VBA. Just copy the entire top block, in this case three rows, and then paste immediately underneath. Then sort by the first ID column, which will group the original row with its copy. Finally, generate a new ID sequence down all rows starting with one at the top. As a series of steps:
Copy original data and paste underneath
Sort new + copy data on the number ID column
Generate a new ID column starting with 1 at the first row
Maybe you can do it like this:
Copy whole table to another sheet
Create an id column for both table
Give odd id number for the main table and give even id number for the copied table
Copy and paste copied table to main table and sort main table by id and then remove id column and delete copied sheet.
With vba assuming no gaps in range
Option Explicit
Sub Testing()
Dim targetRange As Range
Dim sourceData()
With ActiveSheet.Range("A1").CurrentRegion
sourceData = .Value2
Set targetRange = .Resize(.Rows.Count * 2, .Columns.Count)
End With
Dim currValue As Long
Dim counter As Long
counter = 1
For currValue = LBound(sourceData, 1) To UBound(sourceData, 1)
targetRange.Cells(counter, 1).Resize(2, UBound(sourceData, 2)) = Application.WorksheetFunction.Index(sourceData, currValue, 0)
counter = counter + 2
Next currValue
End Sub
Source data in A1:B3
How want to implement a function in Excel that can count the dependents for a given cell.
Example, suppose the following data:
| | A | B | C |
| 1 | |=A4|=A4|
| 2 | |=A4|=A4|
| 3 | | | |
| 4 |foo|=DEPENDENTCOUNT(A4)
In, cell B4, I want to show the number of time the cell A4 was referenced. With this table, it should 4, since =A4 was used 4 times.
I have tried the following function, but it always returns 1:
Function DEPENDENTCOUNT(cell) As Integer
DEPENDENTCOUNT = cell.Dependents.Count
End Function
Any idea?
First there is a spelling error in the UDF():
Function DEPENDENTCOUNT(cell As Range) As Integer
DEPENDENTCOUNT = cell.Dependents.Count
End Function
Secondly, that Property will work within a Sub, but not within a UDF():
Sub qwert()
MsgBox Range("A1").Dependents.Count
End Sub
I'm learning vba and I have an excel table which looks like this:
Range |max | min| discount%
R1 |0 | 9| 0
R2 |10 | 19| 10
R3 |20 | 100| 20
From another excel sheet, I have a field quantity purchased from which I want to retrieve the range coming from this table.
E.g
if qty = 6 then R1, if qty = 56 then R3
and so on
This is normally not so difficult with a vlookup when my table is static. My problem is the fact that the number of ranges can change (due to a macro I wrote). Here it's 3 ranges, but we can have more or less ranges with different values. Can someone please help?
When you're trying to evaluate multiple things you can use "And" in VBA Its just like the excel version, both expressions must return true for you to receive a True answer.
This should get you going in the right direction,
Basic logic
a = b : a equals b
a <= b : a is less than or equal to b
a >= b : a greater than or equal to b
a < b : a is less than b
a > b : a is greater than b
a <> b : a is not equal to b
Sub ranger()
If Range("A1") > 1 And Range("A1") < 3 Then
MsgBox True
Else
MsgBox False
End If
End Sub
Put 2 in cell A1
I have a huge (~950 variables) survey response spreadsheet, made 2-4x larger than it needs to be because each item's individual response options are reported in separate columns. E.g., If Question 2 is in cell A1 and has 3 response options, these are listed below the question in cells A2-C2, A3-C3, etc. Note: Only one of A2-C2, etc. is filled w/ data for each observation.
It seems clear that I could go through the spreadsheet manually and concatenate A2-C2 using code similar to this:
=CONCATENATE(IF(ISBLANK(A4),"",A4),IF(ISBLANK(B4),"",B4),IF(ISBLANK(C4),"",C4))
But, the above requires manually altering the code (questions have anywhere from 2-6 response options) and copying/pasting it through all observations for each of the 960 variables individually. Because I'd like to finish this before dying of old age, I'd love to have some way of automating the above process.
It would be easy enough to go through and insert an identifier column (w/ no data but w/ some obvious 1st row name) after each variable's last response option so the code knows where to begin looking back for data to concatenate. The code would have to know to stop whenever it hits the previously concatenated result, and begin the current concatenation w/ the subsequent column. Once it hits a certain line (say, 60? I only have ~55 observations), it could just look for the next identifier column and repeat the process.
Any ideas would be much appreciated.
I need to check for blanks so as to not have extra spaces in the data (to aid future analysis).
Hopefully the below will clarify the situation further. You're correct in your earlier comment; each question is followed by 55 rows of observations. For example:
| | Q1 | | || Q2 | ||
|-|--------|---------|--------||---------|--------||
|1| 1 | | || | 2 ||
|2| | 2 | || | 2 ||
|3| | | 3 || | 2 ||
|4| | 2 | || 1 | ||
|5| | | 3 || | ||
|6| 1 | | || | 2 ||
|7| 1 | | || 1 | ||
|8| | | 3 || 1 | ||
|9| | 2 | || | 2 ||
There isn't currently a blank column after the last response option for each question, but (as mentioned in the initial post) I can easily throw one in.
I'm not 100% sure I understand your layout, but you can greatly simplify the concatenation by using & as follows:
=A4&B4&C4
this would have the same effect as your code, and does not require the checks for blank cells.
I'll tackle the rest of the question as information becomes available.
edit: Here's my solution. I'm assuming that the questions are in row 1, and the first set of observations is in row 2, so the last set of observations falls in row 56.
type the number 1 into the cell A58
place the formula: =IF(ISBLANK(B1),A58,A58+1) into cell B58
fill this formula right all the way across all of your questions
in cell A59, enter the formula =MATCH(COLUMN(),58:58,0)
in cell A60, enter the formula =MATCH(COLUMN(),58:58,1)
in cell A61, enter the formula =INDEX(1:1,,A59)
fill all three of these formulas right for 17 cells (assuming you have 17 questions)
in cell A62, enter the formula =SUM(INDIRECT(ADDRESS(ROW(A2),A$59)&":"&ADDRESS(ROW(A2),A$60)))
fill this formula across 17 cells, and down 55 cells.
Here's how it would look for three questions:
| A | B | C | D | E | F | G |
|----|------------------------------------------
| 1 | Qn1 Qn2 Qn3
| 2 | 1 2 1
| 3 | 2 2 2
| .. |
| 58 | 1 1 1 2 2 3 3
| 59 | 1 4 6
| 60 | 3 5 8
| 61 | Qn1 Qn2 Qn3
| 62 | 1 2 1
| 63 | 2 2 2
#EJames: Thanks for the suggestion & pointer to lay out the example graphically. I need to check for blanks so as to not have extra spaces in the data (to aid future analysis).
Hopefully the below will clarify the situation further. You're correct in your earlier comment; each question is followed by 55 rows of observations. For example:
| | Q1 | | || Q2 | ||
|-|--------|---------|--------||---------|--------||
|1| 1 | | || | 2 ||
|2| | 2 | || | 2 ||
|3| | | 3 || | 2 ||
|4| | 2 | || 1 | ||
|5| | | 3 || | ||
|6| 1 | | || | 2 ||
|7| 1 | | || 1 | ||
|8| | | 3 || 1 | ||
|9| | 2 | || | 2 ||
There isn't currently a blank column after the last response option for each question, but (as mentioned in the initial post) I can easily throw one in.
Much obliged.
The fastest way:
Add an new column after column D
Put 'Q1' in cell B1
Put the following formula in: =SUM(B2:D2)
Copy the formula down to the last row
Repeat the steps above for all questions
Select all data (ctrl-*)
Copy the selection
Choose 'Paste Special' from the context menu and choose 'values'
Delete the original columns
If you want you can create a macro that does this automatically.
Here is the macro. It is my no means my best piece of coding ever. What would you expect in 15 minutes. It does the job, although it crashes when finished. ;o)
Open your excel sheet
Make a back up copy
Hit Alt-F11
Insert a new module
Paste the code below
Put the cursor inside the macro
Hit F8 to step through the code
Since you are in Stack Overflow I assume you will be able to adjust the macro to further tailor your needs.
Sub Main()
Dim ColumnsCount As Integer
ColumnsCount = Range("A1").CurrentRegion.Columns.Count
For i = 2 To 20000
Dim CurrentCell As Range
Set CurrentCell = Range("A1").Offset(0, i - 1)
If CurrentCell.Value <> "" Then
CurrentCell.Select
Selection.End(xlToRight).Select
Dim AnswersCount As Integer
AnswersCount = Selection.Column - CurrentCell.Column
CurrentCell.Offset(0, AnswersCount).Select
Selection.EntireColumn.Insert
Selection.Value = CurrentCell.Value
i = i + AnswersCount
Selection.Offset(1, 0).Select
Selection.FormulaR1C1 = "=SUM(RC[" + CStr(AnswersCount * -1) + "]:RC[-1])"
Selection.Copy
Range(Selection, Selection.Offset(100, 0)).Select
ActiveSheet.Paste
Selection.EntireColumn.Select
Application.CutCopyMode = False
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
End If
Next i
End Sub
Thanks for the piece of information. Apart from your way one can also use the & character for concatenation, so instead of: =concatenate(B1,” “,C1,” “,D1) you could use: =B1 & ” ” & C1 & ” ” & D1
Old post but I made this function to concatenate cells. Works similar to SUMIF.
Function CONCIF(rng As Range, criteria As Range, sums As Range)
'Function to concatenate a range of cells if the chosen adjacent cells matches
'the criteria.
'To use:
' Copy and Paste this into a module in VB Editor
' In a cell type =CONCIF(rng, criteria, sums) where:
' rng is the range of cells to match the criteria
' criteria is the value you would to match
' sums is the range of cells to concatenate if criteria matches
' To change what is put between the concatenations, edit the " / " below and put
' whatever you would like in between the quotes.
' Enjoy! -RP
Dim rCell As Range
Dim concat As String
Dim dist As Integer
dist = sums.Column - rng.Column
concat = ""
For Each rCell In rng
If rCell = criteria Then
If concat = "" Then
concat = rCell.Offset(0, dist).Value
Else
concat = concat & " / " & rCell.Offset(0, dist).Value
End If
End If
Next rCell
CONCIF = concat
End Function
Or if you want just a simple way to select a horizontal range and have it concatenate the non-blank cells:
Function CONCIF(rng As Range)
Dim rCell As Range
Dim concat As String
Dim dist As Integer
dist = 0
concat = ""
For Each rCell In rng
If rCell.Value <> "" Then
If concat = "" Then
concat = rCell.Value
Else
concat = concat & ", " & rCell.Value
End If
End If
Next rCell
CONCIF = concat
End Function