Excel: Create summary worksheet using certain cells from other worksheets - excel

I have a whole bunch of tabs which share a standard structure. In cells A1, B1, C1 of each tab, I have, respectively, an ID number, a first Name and a surname. There is a whole bunch of other information on each tab that is not relevant to the question.
I want to create a summary tab, with a 3-column table carrying only the ID number, first name and surname from each of the other tabs. Again, these are always in cells A1, B1, C1. I also want the id number in the summary table to hyperlink to the appropriate tab.
Is there any way to semi-automate this using cell references? Like how, in a single table, if you enter a number in a cell and drag downwards, the number will be incremented in each consecutive cell in the column. Is there any way to achieve a similar effect, but with the cell reference remaining constant (always cell A1, A2, A3) and the TAB reference being incremented? In short, is there any way to tie a particular row to a separate tab (in a way that will take care of the hyperlinking, also)? Or do I have to enter the reference manually for each table?
Not that the tabs are not labelled Sheet 1, Sheet 2 etc. They will be labelled with the name of the person whose information they hold.

[EDIT: Added ASAP option]
ASAP utilities takes the hard work out of this
Download ASAP utilities , http://www.asap-utilities.com/
Run the utility as per screenshot 1 below
Chose whether you want a live link summary, or hardcoded report
(screenshot 2)
ASAP settings
Select your A1:C1 accross sheets
Output
[Initial Post]
You can do this without a continuous VBA sub
Step 1
Define a range name to contain all the sheet names, (from this great example from David Hager)
In this example I used
AllSheets
with a reference of
=RIGHT(GET.WORKBOOK(1),LEN(GET.WORKBOOK(1))-FIND("]",GET.WORKBOOK(1)))
Step 2
Use an INDEX formula to pull out each unique sheet on your summary sheet
=IF(ROW()<=COUNTA(AllSheets),INDEX(AllSheets,ROW()),"")& LEFT(RAND(),0)
Assuming your summary sheet is at the far left (ie sheet 1) then
ROW() will be 2 in A2, so this will pull the second sheet from AllSheets
ROW() will be 3 in A3, so this will pull the third sheet from AllSheets etc
The LEFT(RAND(),0) ensures that the sheet name list updates as soon as any sheet name is changed (and VBA solution would need to monitor the sheet names for changes)
Step 3
Use INDIRECT to pull out A1, B1 and C1 for each sheet
=IF($A2<>"",INDIRECT("'"&$A2&"'!"&B$1),"")
Copy this B2 formula to the right and down as far as you expect potental sheet names
Note that this formula handles the ' that occur for sheet names with spaces etc

You could probably use the INDIRECT function.
For example, to get the value of cell A1 on sheet John, you can call:
=INDIRECT("John!A1")
So in your case you could put "John" in cell A1 of your summary tab, "A1" in cell B1 of the summary tab and in cell C1, put the following formula:
=INDIRECT("'"A1&"'!"&B1)

There is no function built into excel that will give you all the sheet names in the workbook. For this you would have to turn to VBA, the scripting facility built into Excel. If you are on Office 2007 or above, this would require you to store your workbook in a special format. Also, to execute the macro, the user has to specifically allow macro execution. The following macro will allow you to print all sheet names in the first column. An important point to note is that this code would have to be executed in the code window of the summary sheet.
Sub SheetNames()
For i = 1 To Sheets.Count
Cells(i, 1) = Sheets(i).Name
Next i
End Sub
Once you have the names of the sheet, you can dynamically link to the cells in the sheets by using the following formula:
=INDIRECT(ADDRESS(1, 1, 1, 1, A1))
=INDIRECT(ADDRESS(1, 2, 1, 1, A1))
=INDIRECT(ADDRESS(1, 3, 1, 1, A1))
The INDIRECT formula takes an address. The ADDRESS formula works as follows ADDRESS(Row_num, Column_num, Abs_num, A1, Sheet_text). Excel help will be able to answer any questions.
You could setup the formula and run the macro only when there are a lot of new sheets. The workbook can then be stored without the macro. Just keep the macro in a text file somewhere in case you need it again.

Here's a solution using a VBA UDF to get the sheet names. It includes a Hyperlink as requested.
The call to the UDF is placed in an out of the way column. I've used H for this example
Place these functions in cells A1, B1, C1, H1
A1: =IF(H1<>"",HYPERLINK(SUBSTITUTE(H1,"]","]'")&"'!A1",INDIRECT("'"&$H1&"'!R1C[0]",FALSE)),"")
B1 and C1: =IF($H1<>"",INDIRECT("'"&$H1&"'!R1C"&COLUMN(),FALSE),"")
H1: =SheetByIndex()
Put this in a VBA module
Function SheetByIndex() As Variant
Application.Volatile
Dim r As Range
Dim shIdx As Long
Dim ThisShIndex As Long
Dim sh As Worksheet
Dim wb As Workbook
Set r = Application.Caller
ThisShIndex = r.Worksheet.Index
shIdx = r.Row
If shIdx >= ThisShIndex Then
shIdx = shIdx + 1
End If
Set wb = r.Worksheet.Parent
On Error Resume Next
Set sh = wb.Worksheets(shIdx)
If Err.Number <> 0 Then
SheetByIndex = ""
Else
SheetByIndex = "[" & wb.Name & "]" & sh.Name
End If
End Function
Copy formulas in A, B, C, H down as far as required

My slightly differnt approach, based on the code published here (there's a sample sheet there, too, for testing):
Option Explicit
Sub CreateHyperlinkedSheetList()
'Author: Jerry Beaucaire
'Date: 1/3/2011
Dim ws As Worksheet, NR As Long
Application.ScreenUpdating = False
With ActiveSheet
NR = .Range("A" & Rows.Count).End(xlUp).Row + 1
For Each ws In ActiveWorkbook.Worksheets
If ws.Name <> .Name Then
.Range("A" & NR).Value = ws.Range("A1").Value
.Hyperlinks.Add Anchor:=.Range("A" & NR), Address:="", SubAddress:= _
"'" & ws.Name & "'!A1", TextToDisplay:=ws.Name
.Range("B" & NR).Value = ws.Range("B1").Value
.Range("C" & NR).Value = ws.Range("C1").Value
NR = NR + 1
End If
Next ws
End With
Application.ScreenUpdating = True
End Sub

Related

VBA to assign data according of two columns from workbook 1 to workbook 2

I need a help and your wide experiences please.
Lets imagine a case:
Three Workbooks exists: Workbook1 & Workbook2 & Workbook3
The Workbook1 & Workbook 2 has two same columns: ColumnA & ColumnB (for Workbook1) & ColumnAA & ColumnBB (for Workbook2)
All data are unsorded.
All columns has a different number of rows.
Macro in Workbook3 will be run and assign data from Workbook1 according of ColumnA & ColumnB to Workbook2 to ColumnCC & ColumnDD.
No auxiliary columns are allowed.
I am solivng it now by the simple VLOOKUP macro column by column. But I am still geting same values in ColumnCC & ColumnDD. It means that a all found values are same according of first found value in ColumnC & ColumnD but there are different values in that columns after all. And I stucked just here because I do not know how to solve it by macro.
The result what I need to get on is shown on attached picture below.
Curently I am try to solve it using a combination of the functions IF & VLOOKUP but i do not know how to build the macro fot this case of two functions and I did not find a relevant example to rewrite it by analogous.
=IF(B:B="ano";VLOOKUP(A:A;[Workbook1.xlsx]Sheet1!$A:$D; 3; 0); "")
Result example & combined formula IF+VLOOKUP
I would be grateful for your help or find another simple way using a macro.
Thank you so much.
Example which hopefully can get you start.
Book1:2 is your Workbook2.xlsx - Book1:1 is your Workbook1.xlsx
On both workbooks, the rows value under HDR2 (column B) is either blank or "ano". Nothing else, no rows with value other than "ano" under HDR2 in both workbooks.
The expected result in Workbook2.xlsx :
Regarding the blue and yellow color as seen from the image above,
there is no result in HDR3 and HDR4 in book2 - because
Blue : fff has no ano in book2 although fff has ano in book1.
Yellow : although ggg has ano in book2, but ggg in book1 has no ano.
If that's the kind of result you expect, the code is something like this :
Sub test()
Dim wb1 As Workbook: Dim wb2 As Workbook
Dim rgWb1 As Range: Dim rgWb2 As Range
Dim cWb1 As Range: Dim cWb2 As Range
Dim concWb1 As String: Dim concWb2 As String
Set wb1 = Workbooks("Book1.xslx") 'change as needed
Set wb2 = Workbooks("Book2.xslx") 'change as needed
With wb1.Sheets("Sheet1") 'change as needed
Set rgWb1 = .Range("A2", .Range("A" & Rows.Count).End(xlUp)).Offset(0, 1)
End With
With wb2.Sheets("Sheet2") 'change as needed
Set rgWb2 = .Range("A2", .Range("A" & Rows.Count).End(xlUp)).Offset(0, 1)
End With
For Each cWb2 In rgWb2.SpecialCells(xlCellTypeConstants)
concWb2 = cWb2.Offset(0, -1).Value & cWb2.Value
For Each cWb1 In rgWb1.SpecialCells(xlCellTypeConstants)
concWb1 = cWb1.Offset(0, -1).Value & cWb1.Value
If concWb2 = concWb1 Then
cWb2.Offset(0, 1).Value = cWb1.Offset(0, 1).Value
cWb2.Offset(0, 2).Value = cWb1.Offset(0, 2).Value
Exit For
End If
Next
Next
End Sub
The process:
It set the data range under HDR2 for both workbooks, as rgWb1 and rgWb2 variable. As the "rule" I've said before, since the rows under HDR2 will be only either blank or "ano" in both workbooks, so the code loop only to each cell (as cWb2 variable) which has value in rgWb2, concat the cWb2 value with the cell to the left value as concWb2.
Then it loop to each cell (as cWb1 variable) which has value in rgWb1 and also do the concat the cWb1 value with the cell to the left value as concWb1.
It check if concWb2 value = concWb1 value, then it put the value of cWb1.Offset(0, 1) to cWb2.Offset(0, 1) and put the value of cWb1.Offset(0, 2) to cWb2.Offset(0, 2).
FYI, with the "rule" for the rows under HDR2 in both workbooks like that, actually the code doesn't need to do the concatenate (concWb1 and concWb2). Anyway, I just have it to do the concatenate.
Please note, the code assumed that the data under HDR1 in both workbooks are all unique.

Copying cells with Range.Copy

I'm writing an Excel workbook to take data for a research study, analyze each day's worth, then send the entered data and its 7 summary computations into a workbook (named test subject 1, and worksheet test med 1) for archive and analysis.
The range.copy command correctly copies the range of the data entered directly (or by a Userform) and the cells with the descriptive titles.
The column P, which contains data referenced from another sheet in the Workbook, is copied with the wrong cell reference. Cell AB16 is copied with the data from ='[FAVor Study Medication Daily Calculator8.xlsm]Calculations'!AB7, (not ...AB16). This is true for all the 7 summary cells in that column (AB16 - AB22), but cells ab15 and ab23, simple references to other cells on the same worksheet, are correctly copied.
I tried using the PasteSpecial command but got another set of problems that I'll try to solve next!
I've labelled the problem line of code as ProblemLine:
Dim wsCopyfrom As Worksheet
Dim wsCopyto As Worksheet
'Dim CopyfromLastRow As Long
'Dim CopytoLastRow As Long
'set variables for copy and dest sheets
Set wsCopyfrom = ThisWorkbook.Sheets("EnterData")
Set wsCopyto = ActiveWorkbook.Sheets(medname)
'Find last used row in the copyfrom based on data in column E and the copyto Col A
CopyfromLastRow = wsCopyfrom.Range("E200").End(xlUp).Row
CopytoLastRow = wsCopyto.Range("A200").End(xlUp).Row
'make copy of range, but ensure that all of the block rows are included, to row 10
If CopyfromLastRow > 19 Then
wsCopyfrom.Range("A7:P" & CopyfromLastRow).Copy wsCopyto.Range("A" & CopytoLastRow + 1)
Else
'ProblemLine
wsCopyfrom.Range("A7:q20").Copy wsCopyto.Range("A" & CopytoLastRow + 1)
End If 'if to copy at least to row 19
This is expected "Relative Reference" behviour. Same thing would happen if you manually copied those ranges in Excel yourself.
Two option to solve this:
Change your formula on the sheet to "Absolute References" eg ='[FAVor Study Medication Daily Calculator8.xlsm]Calculations'!$AB$16
Change your code to not use Copy, eg
wsCopyto.Range("A" & CopytoLastRow + 1).Formula = wsCopyfrom.Range("A7:Q20").Formula

Is there a way to use the sheet name from a certain cell (which has been populated using that sheet) to populate another cell?

Let me try to be more clear:
Here's an image that illustrates what I'm trying to do.
Essentially, my goal would be to have a formula that I could put into cell A2 (or a macro, if necessary) that would insert the name of the sheet that cell B2 comes from. In this case, that would be Sheet2. I've tried a bit through the macro recorder, but I haven't been able to get anything to work the way I want it to.
Ideally, I'd be able to select a cell (in this case, cell A2) and activate a macro or put in a formula that would populate that cell (A2) with the Sheet that the cell to the right of it (B2) comes from.
Thanks a ton for your help, any guidance as to what I should use for this or how I could do this would be hugely appreciated.
Here's a UDF that will pull the sheet name for a simple =SheetX!RANGE formula. It will also alert if there are multiple sheet references or none at all.
Place this in a standard module and in a cell type =ReturnSheet(B2)
Function ReturnSheet(rng As Range) As String
Dim sFormula As String
sFormula = rng.Formula
If InStr(1, sFormula, "!") = 0 Then
Dim sSheet As String
sSheet = "No sheet precedents found!"
Else
If UBound(Split(sFormula, "!")) = 1 Then
sSheet = Mid(sFormula, 2, InStr(1, sFormula, "!") - 2)
Else
sSheet = "Multiple Sheet precendents!"
End If
End If
ReturnSheet = Replace(sSheet,"'","") 'replace single quote in sheet names that has spaces
End Function

If/Then/Replace formula

I know VBA is probably the way to go but I believe this can be done using a few basic formulas.
I need "E2" to be replaced (cut/copy) with the contents from "A3" but only if "D2" = "Status:Active"...and so on down the sheet
the yellow and blue color-coding are only for this example and do not represent the whole sheet
this is a 7,000 line spreadsheet that was a report generated off some old system and I'm trying by best to collate and format.
Try in Column F starting with cell F2
=if(AND(E2="",D2="Status: Active"), A2, E2)
This will test to see if D2 has "Status: Active" and if it does, it will pull the value form A2. If it isn't then it will use the address already in E2
As explained in your comments that you are looking for A to be blank when F accepts a value from it (Cut/Paste)... there is no way for a formula to affect another cell, but... You could add a new Column B inserted after A and put the following formula in there: =if(A2<>G2, "", A2). Then hide Column A. The new B column will then only show values of Column A when it's not already in Column G (formerly column F before the insertion of the new column).
You could also do all of this through VBA, but that seems like more effort than it's worth when some simple formulas will get you there.
Seeing as you want the column A to be blank you can try this macro out:
Option Explicit
Sub SwapCols()
Dim oWs As Worksheet
Dim lRowNum As Long
Dim i As Long
Set oWs = ActiveWorkbook.Worksheets("Sheet1")
lRowNum = oWs.Range("A2").End(xlDown).Row
For i = 2 To lRowNum
If oWs.Range("D" & CStr(i)).Value = "Status:ACTIVE" Then
oWs.Range("E" & CStr(i)).Value = oWs.Range("A" & CStr(i)).Value
oWs.Range("A" & CStr(i)).Value = Null
End If
Next i
End Sub
Make sure you replace "Sheet1" with the name of your sheet. the macro basically checks if a cell in column D has the value "Status:ACTIVE" and if it does it copies the corresponding cell in column A to column E.
Just make sure if you do run this and you do not like the results do not save.

Find Maximum Value for a column in different sheets and report it in result sheet

I want to check Column A (A1:A365) in Sheet2, Sheet3, Sheet4 and Sheet5 and find Maximum value for each cell. Compare A1 in Sheet2, Sheet3, Sheet4 and Sheet5, find maximum of it and report it in A1 in result page. Also in cell B1 report corresponding sheet for this maximum. This goes on to Column A (A1:A365)
the following code i used:
Worksheets("sheet2").Range("A1").Value = a
Worksheets("sheet3").Range("A1").Value = b
Worksheets("sheet4").Range("A1").Value = c
Worksheets("sheet5").Range("A1").Value = d
MaxValue = Application.Max(a, b, c, d)
Range("A1").Value = MaxValue
yes i have just 4 sheets – Mohsen 11 mins ago
Non VBA Solution
In Sheet1, Cell A1, put this formula
=MAX(Sheet2!A1,Sheet3!A1,Sheet4!A1,Sheet5!A1)
In Sheet1, Cell B1, put this horrifying formula. I am sure there is a better way to find the sheet name though.
=IF(Sheet1!A1=Sheet2!A1,RIGHT(CELL("filename",Sheet2!A1),LEN(CELL("filename",Sheet2!A1))- FIND("]",CELL("filename",Sheet2!A1),1)),IF(Sheet1!A1=Sheet3!A1,RIGHT(CELL("filename",Sheet3!A1),LEN(CELL("filename",Sheet3!A1))- FIND("]",CELL("filename",Sheet3!A1),1)),IF(Sheet1!A1=Sheet4!A1,RIGHT(CELL("filename",Sheet4!A1),LEN(CELL("filename",Sheet4!A1))- FIND("]",CELL("filename",Sheet4!A1),1)),IF(Sheet1!A1=Sheet5!A1,RIGHT(CELL("filename",Sheet5!A1),LEN(CELL("filename",Sheet5!A1))- FIND("]",CELL("filename",Sheet5!A1),1)),""))))
A word of caution though. To use the RIGHT(CELL("filename",Sheet2!A1),LEN(CELL("filename",Sheet2!A1))- FIND("]",CELL("filename",Sheet2!A1),1)), you need to have the workbook saved.
My Sheet2, A1 has 1, Sheet3, A1 has 2, Sheet4, A1 has 2.5,Sheet5, A1 has 3
VBA Solution
Sub Sample()
Dim ws As Worksheet
Dim i As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
.Range("A1:A365").Formula = "=MAX(Sheet2!A1,Sheet3!A1,Sheet4!A1,Sheet5!A1)"
.Range("A1:A365").Value = .Range("A1:A365").Value
For i = 1 To 365
Select Case .Range("A" & i)
Case ThisWorkbook.Sheets("Sheet2").Range("A" & i).Value: .Range("B" & i).Value = "Sheet2"
Case ThisWorkbook.Sheets("Sheet3").Range("A" & i).Value: .Range("B" & i).Value = "Sheet3"
Case ThisWorkbook.Sheets("Sheet4").Range("A" & i).Value: .Range("B" & i).Value = "Sheet4"
Case ThisWorkbook.Sheets("Sheet5").Range("A" & i).Value: .Range("B" & i).Value = "Sheet5"
End Select
Next i
End With
End Sub
Quick solution
Based on Sidd's answer, here's my non-VBA solution without the horrifying formula:
Place this formula in Sheet1!A1: =MAX(Sheet2:Sheet5!A1)
As the sheet name does not have to be flexible (I'd assume you don't change it that often), you can use this formula in B1:
=IF(Sheet2!A1=A1,"Sheet2",
IF(Sheet3!A1=A1,"Sheet3",
IF(Sheet4!A1=A1,"Sheet5",
"Sheet5")))
More structural solution (better suited for many worksheets):
If you have many worksheets, you could consider this alternative.
Have a list of the relevant worksheets stored somewhere in your worksheet. (in the example, I place the list in E3:E7). Name this range Sheets. (Similar to Sidd's horrifying formula, I used the CELL formula to dynamically get each sheet name. However, this is not necessary in a static model)
(same as step 1 above): Place this formula in Sheet1!A1: =MAX(Sheet2:Sheet5!A1)
Place this formula in A2:
=INDEX(Sheets,MATCH(1,COUNTIF(INDIRECT("'"&Sheets&"'!A1"),A1),0))
Enter it as an array formula, i.e. press Ctrl-Shift-Enter instead of Enter.
I uploaded the second solution here.
Kudos to this instruction!
Since the formula is intended to be copied down, you don't want to hard-code a reference to cell A1 in the INDIRECT in Peter Albert's formula. You can use CELL("address",A1) to get a reference to A1 that can be copied down instead.
You can also avoid the need to array-enter the formula by using LOOKUP to return the result instead of INDEX & MATCH.
Note that LOOKUP will return the name of the last worksheet with the max value in case of a tie.
The following formulas use a named range Sheets with the names of each worksheet
=MAX(Sheet2:Sheet5!A1) returns max value (identical to Peter Albert's formula)
=LOOKUP(2,1/COUNTIF(INDIRECT("'" & Sheets & "'!" & CELL("address",A1)),A1),Sheets) returns name of sheet with max value
Make two new sheets with one titled "First" and the other "Last". Make new sheets for your project originate through a button that contains a macro to add duplicate sheets between "First and Last". Then just put one of these simple formulas for example in your reporting cell: =SUM(First:Last!K28) or =MAX(First:Last!K28)

Resources