In excel, I have several sheets (around 50), each with an identical header in columns A, B and C, and then up to 199 rows of data (row 1 = header, rows 2-200 = data). The naming routine is as Wk 1 Mon, Wk 2 Tue, etc, all the way up to Wk 10 Fri
What I would like to do is display all of the data from these tabs in one list, on one sheet. I could potentially do this by referencing each cell from each sheet, one under the other, but the problem is that not all sheets actually have data right the way down to row 200 (some have just the header), and I wish to skip empty rows.
I have absolutely no clue how to approach this in Excel. My understanding of VLOOKUP and the like is rudimentary at best; I'm not sure if I could even achieve what is required by using that family of functions.
I've also looked in to the Consolidation feature of Excel, but I don't think that is what I need in this scenario.
Could someone please suggest how I may achieve my goals. I would prefer to do this via worksheet only functions, but I'd be open to VBA if there was an easy enough solution.
Try this bit of VBA. It basically scrolls through each worksheet, finds the last row and pastes it on the bottom of the first sheets data. It's a bit crude in methodology but it does work!
Dim ws As Worksheet
For Each ws In Worksheets
i = i + 1
If i = 1 Then
FirstSheet = ws.Name
ElseIf i > 1 Then
ws.Activate
LastCell = Cells(65536, 1).End(xlUp).Row
Range("A1:C" & LastCell).Select
Selection.Copy
Worksheets(FirstSheet).Activate
Cells(Cells(65536, 1).End(xlUp).Row + 1, 1).Select
ActiveCell.PasteSpecial xlPasteValuesAndNumberFormats
End If
Next ws
Related
Update: sample sheet provided here: https://docs.google.com/spreadsheets/d/1BapXdaVOUL634SstNJXqYNocsD_EvvtlbJ77vlElmZs/edit?usp=drivesdk. Any help will be appreciated!
Hi fellow nerds.
I'm trying to make the current column (most recent interaction date with client) display the max values (most recent dates) from ContactLog!b:b (dates of all recorded interactions), when the client name in ContactLog!A:A matches to the client name in current row column A.
After many days of trying, I've found several formulas to successfully achieve this result for the current cell only.
=MAXIFS(ContactLog!B:B, ContactLog!A:A, A:A)
=MAX(FILTER(ContactLog!B4:B, ContactLog!A4:A=VLOOKUP(A2, ContactLog!A4:B, 1, FALSE)))
=MAX(QUERY(ContactLog!A4:B, ""SELECT B WHERE A = '""&VLOOKUP(A2, ContactLog!A4:B, 1, FALSE)&""'"", 0))
=IF(COUNTIF(ContactLog!A:A, A2),MAX(FILTER(ContactLog!B:B, ContactLog!A:A = A2)),"")
But none of these seem to work with arrayformula, to spread to the entire column. I'd like this result to apply automatically to the entire column (wherever column A is not blank).
It's displaying the correct max value for the first cell (in which the formula is written), and I could drag the formula down, but not spreading automatically as an array.
I've tried using =match with =filter, but that keeps running into mismatched range row sizes. (I've previously solved that by using filter within a filter, but can't figure that out here).
[I have a similar issue for the nearby columns also, "most recent interaction method", and "reminders & goals". The formula there is:
=INDEX(ContactLog!C:C, MATCH(MAX(IF(ContactLog!A:A=A2, IF(ContactLog!B:B=MAX(IF(ContactLog!A:A=A2, ContactLog!B:B)), ROW(ContactLog!B:B)))), ROW(ContactLog!B:B), 0))
And
=IFERROR(CONCATENATE(JOIN(" • ",FILTER(ContactLog!D:D,ContactLog!A:A=A2, ContactLog!D:D<>"")),IF(INDEX(ContactLog!D:D,MAX(IF(ContactLog!A:A=A2,ROW(ContactLog!D:D))))="","","")),"")
They both work great, but I can't get them to work with arrayformula...]
What am I missing?
You can do something like this with BYROW, that allows you to expand your formula through the column and be calculated "row by row". Using your first option:
=BYROW(A:A, LAMBDA (each,IF(each="","",MAXIFS(ContactLog!B:B, ContactLog!A:A, each))))
Sorry for the somewhat long title, but I was told to be as specific as possible. :D
My problem will require some explantion.
So, I have 2 spreadsheets files ("Konverteringstabeller" and "Tee Posen").
In "Tee Posen" I have a sheet named "Scores MIK" (golf scorecard and my name).
In "Konverteringstabeller" I have sheets with conversion tables for multiple golf courses, but if one works, all should.
What I need is to find out what course handicap I would get if my golf handicap is "HCP 26,0" (as shown in File 2 Picture), and in this case that result should be 29 (not visible), but you should get the point.
(example: golf hcp 10 would result in course hcp 11, because 10 is between 9,9-10,7)
While I have been able to find the right result, it has only been in the "Konverteringstabeller" spreadsheet file and that is not the place I need it.
I want to have it written in E6 in the "Scores MIK" sheet in File 2.
I should mention that in "Scores MIK : File 2", cell C2 (Ikast Golf Klub) has data validation so I can easily change between the different courses in the "Konverteringstabeller" file once I add more.
What I have been messing with is something with vlookup and importrange with concatenate in it, but I can't figure out how to do it, so I ask for your help.
And I am by no means skilled in the art of Spreadsheets, so I would very much appreciate a detailed explanation.
Picture - Scores MIK (File 2)
Picture - Ikast Golf Klub (File 1)
Thanks in advance!
// Mikkel Christensen
OK so a couple notes - One is that to join a static cell where you keep the sheet name but allow it to chance you should add '$' around it, also if the rows for B8-E70 will always be the same position on the various sheets you also need to add $ around those as well.
here is an example of the whole formula
=IFERROR(ARRAYFORMULA(VLOOKUP(E5:E25;IMPORTRANGE("spreadsheet key";"'"&C2&"'!$B$8:$E$70");4;TRUE)))
And lastly - using the "&" operator to concatenate is better at least in my opinion because concatenate sometimes does not work as well with array formula - plus I find it personally quicker and easier to use that having wrap yet another function around my stuff.
I want to build kind of an automatic system to update some race results for a championship. I have an automated spreadsheet were all the results are shown but it takes me a lot to update all of them so I was wondering if it would be possible to make a form in order to update them more easily.
In the form I will enter the driver name and the number o points he won on a race. The championship has 4 races each month so yea, my question is if you guys know a way to update an existing data (stored in a spreadsheet) using a form. Lets say that in the first race, the driver 'X' won 10 points. I will insert this data in a form and then call it from the spreadsheet to show it up, that's right. The problem comes when I want to update the second race results and so on. If the driver 'X' gets on the second race 12 points, is there a way to update the previous 10 points of that driver and put 22 points instead? Or can I add the second race result to the first one automatically? I mean, if I insert on the form the second race results can it look for the driver 'X' entry and add this points to the ones that it previously had. Dunno if it's possible or not.
Maybe I can do it in another way. Any help will be much appreciated!
Thanks.
Maybe I missed something in your question but I don't really understand Harold's answer...
Here is a code that does strictly what you asked for, it counts the total cumulative value of 4 numbers entered in a form and shows it on a Spreadsheet.
I called the 4 questions "race number 1", "race number 2" ... and the result comes on row 2 so you can setup headers.
I striped out any non numeric character so you can type responses more freely, only numbers will be retained.
form here and SS here (raw results in sheet1 and count in Sheet2)
script goes in spreadsheet and is triggered by an onFormSubmit trigger.
function onFormSubmit(e) {
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet2');
var responses = []
responses[0] = Number(e.namedValues['race number 1'].toString().replace(/\D/g,''));
responses[1] = Number(e.namedValues['race number 2'].toString().replace(/\D/g,''));
responses[2] = Number(e.namedValues['race number 3'].toString().replace(/\D/g,''));
responses[3] = Number(e.namedValues['race number 4'].toString().replace(/\D/g,''));
var totals = sh.getRange(2,1,1,responses.length).getValues();
for(var n in responses){
totals[0][n]+=responses[n];
}
sh.getRange(2,1,1,responses.length).setValues(totals);
}
edit : I changed the code to allow you to change easily the number of responses... range will update automatically.
EDIT 2 : a version that accepts empty responses using an "if" condition on result:
function onFormSubmit(e) {
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet2');
var responses = []
responses[0] = Number((e.namedValues['race number 1']==null ? 0 :e.namedValues['race number 1']).toString().replace(/\D/g,''));
responses[1] = Number((e.namedValues['race number 2']==null ? 0 :e.namedValues['race number 2']).toString().replace(/\D/g,''));
responses[2] = Number((e.namedValues['race number 3']==null ? 0 :e.namedValues['race number 3']).toString().replace(/\D/g,''));
responses[3] = Number((e.namedValues['race number 4']==null ? 0 :e.namedValues['race number 4']).toString().replace(/\D/g,''));
var totals = sh.getRange(2,1,1,responses.length).getValues();
for(var n in responses){
totals[0][n]+=responses[n];
}
sh.getRange(2,1,1,responses.length).setValues(totals);
}
I believe you can found everything you want here.
It's a form url, when you answer this form you'll have the url of the spreadsheet where the data are stored. One of the information stored is the url to modify your response, if you follow the link it will open the form again and update the spreadsheet in consequence. the code to do this trick is in the second sheet of the spreadsheet.
It's a google apps script code that need to be associated within the form and triggered with an onFormSubmit trigger.
It may be too late now. I believe we need a few things (I have not tried it)
A unique key to map each submitted response, such as User's ID or email.
Two Google Forms:
a. To request the unique key
b. To retrieve relevant data with that unique key
Create a pre-filled URL (See http://www.cagrimmett.com/til/2016/07/07/autofill-google-forms.html)
Open the URL from your form (See Google Apps Script to open a URL)
I’m trying to create either a report or form that displays data in essentially a “calendar” form.
I have a course query that is (simplified) as “Course name”; “course days”; “course times”---
Course; Days; Times
PSY 1; MW; 8A-9A
SOC 150; M; 8A-11A
ANTH 2; Tu; 8A-9A
ANTH 199; MW; 8A-9A
In Access, I’m trying to create a form based on the query that would give me a matrix of the following:
Columns: Times in hour increments
Rows: Days of week
So, for example, with the above data, it would appear like this:
Edit: Yargh, I can't submit an image unfortunately. So, here is a link to a "course schedule" that is essentially what I'm trying to do: Schedule
I have no idea where to start with this. Any tips (or links)?
Edit:
One idea I have is to create a form with a field for every possible cell in the matrix (so, for example, there would be one "Monday, 8-9A" field--and that field would be a filter on the query that ONLY displays results where "day" contains "M" and BeginTime or EndTime or between 8A and 9A). Unfortunately, I'm not sure how to do that.
You can do something close to what you seem to want as an Access form, but it's not easy. This screen capture displays your sample data in a Datasheet View form whose record source is an ADO disconnected recordset. It uses conditional formatting to set the text box background color when the text box value is not Null. Your picture suggested a different color for each Course, but I didn't want to deal with that when more than one Course can be scheduled in the same time block ... my way was simpler for me to cope with. :-)
The code to create and load the disconnected recordset is included below as GetRecordset(). The form's open event sets its recordset to GetRecordset().
Private Sub Form_Open(Cancel As Integer)
Set Me.Recordset = GetRecordset
End Sub
Note I stored your sample data differently. Here is my Class_sessions table:
Course day_of_week start_time end_time
------ ----------- ---------- -----------
PSY 1 2 8:00:00 AM 9:00:00 AM
PSY 1 4 8:00:00 AM 9:00:00 AM
SOC 150 2 8:00:00 AM 11:00:00 AM
ANTH 2 3 8:00:00 AM 9:00:00 AM
ANTH 199 2 8:00:00 AM 9:00:00 AM
ANTH 199 4 8:00:00 AM 9:00:00 AM
This is the function to create the disconnected recordset which is the critical piece for this approach. I developed this using early binding which requires a reference for "Microsoft ActiveX Data Objects [version] Library"; I used version 2.8. For production use, I would convert the code to use late binding and discard the reference. I left it as early binding so that you may use Intellisense to help you understand how it works.
Public Function GetRecordset() As Object
Dim rsAdo As ADODB.Recordset
Dim fld As ADODB.Field
Dim db As DAO.Database
Dim dteTime As Date
Dim i As Long
Dim qdf As DAO.QueryDef
Dim rsDao As DAO.Recordset
Dim strSql As String
Set rsAdo = New ADODB.Recordset
With rsAdo
.Fields.Append "start_time", adDate, , adFldKeyColumn
For i = 2 To 6
.Fields.Append WeekdayName(i), adLongVarChar, -1, adFldMayBeNull
Next
.CursorType = adOpenKeyset
.CursorLocation = adUseClient
.LockType = adLockPessimistic
.Open
End With
strSql = "PARAMETERS block_start DateTime;" & vbCrLf & _
"SELECT day_of_week, Course, start_time, end_time" & vbCrLf & _
"FROM Class_sessions" & vbCrLf & _
"WHERE [block_start] BETWEEN start_time AND end_time" & vbCrLf & _
"ORDER BY day_of_week, Course;"
Set db = CurrentDb
Set qdf = db.CreateQueryDef(vbNullString, strSql)
dteTime = #7:00:00 AM#
Do While dteTime < #6:00:00 PM#
'Debug.Print "Block start: " & dteTime
rsAdo.AddNew
rsAdo!start_time = dteTime
rsAdo.Update
qdf.Parameters("block_start") = dteTime
Set rsDao = qdf.OpenRecordset(dbOpenSnapshot)
Do While Not rsDao.EOF
'Debug.Print WeekdayName(rsDao!day_of_week), rsDao!Course
rsAdo.Fields(WeekdayName(rsDao!day_of_week)) = _
rsAdo.Fields(WeekdayName(rsDao!day_of_week)) & _
rsDao!Course & vbCrLf
rsAdo.Update
rsDao.MoveNext
Loop
dteTime = DateAdd("h", 1, dteTime)
Loop
rsDao.Close
Set rsDao = Nothing
qdf.Close
Set qdf = Nothing
Set GetRecordset = rsAdo
End Function
Actually, if you look at the following video of mine, you can see a calendar created in Access that runs inside of a browser with the new Access Web publishing feature.
http://www.youtube.com/watch?v=AU4mH0jPntI
So, all you really need to do here is format a form with text boxes and setup some code to fill them. VBA or even the above video shows this is quite easy for Access.
I doubt that you will find an easy solution for this problem in Access forms or reports.
The issue is that you need to format different cells differently, and that cells can span multiple rows and have to be merged.
If I were you, I would go in either of these 2 directions:
Drive Excel from Access, because you can format and merge cells independently
Use the Web Browser Control to display HTML that you construct yourself using tables, or a more high-level library like FullCalendar
I would be partial to tryingthe Web Browser and find the right library that can properly format the data.
I know this post is quite old, but I had the same requirement but I got round it by doing the following:
I created a module that would write HTML code (as a text file) to produce the data using a table.
I used the colspan feature of tables to enable me to dynamically produce the view I needed.
The HTML file was created on the Form_Open event and by pointing the webbrowser control to the HTML file the view shows the latest data.
A css file is used to handle the visual display of the HTML file so that it looks similar to the Access forms already in use.
If anyone is interested I can post some code to further illustrate.
I have an excel file, which initially imports stock data from our cloud based accounting program through .iqy web query.
The column headings are:
A1= Quantity B1= Item C1= Description D1= Bin Code
Now I have created a macro which;
Referesh's the data
Range("A1").QueryTable.Refresh False
Delete's all zero stock items
Dim intRow
Dim intLastRow
intLastRow = Range("A65536").End(xlUp).Row
For intRow = intLastRow To 1 Step -1
Rows(intRow).Select
If Cells(intRow, 1).Value = 0 Or Cells(intRow, 1) = "" Then
Cells(intRow, 1).Select
Selection.EntireRow.Delete
End If
Next intRow
Auto Sort by Bin Code
Range("A1:D1").Select
Selection.AutoFilter
Range("A2").Select
Range("A1:D1668").Sort Key1:=Range("D1"), Order1:=xlAscending, Header:= _
xlGuess, OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
Save the Master list
Dim sFileName As String, sPath As String
sPath = "C:\stock\ms\Master List "
sFileName = Format(Now(), "dd'mm'yy")
ActiveWorkbook.SaveAs (sPath & sFileName)
Now this is the tricky bit,
At least 30 items a day need to be checked, however a bin can not be incomplete! So once 30 items have been selected the script needs to check to see if the next item is in the same bin as the 30th item, and include this in the extraction. So lets say item 30 is in bin 10A2, and also item 31, 32, 33, 34, so all in all 34 items (rows) need to be extracted into a new workbook and saved.
This process must start from the previous days sample, so the mechanics should go like this:
look in c\stock\sl\Sample List -1 dd'mm'yy sample list for -1 day, look at the last item bin number, say 10A1,
take the next rows bin number, 10A2,
from the first row which has 10A2, select 30 rows,
Continue till the bin number changes.
save that file as Sample List dd'mm'yy in c\stock\sl\
email Sample List dd'mm'yy to NNN#NNN.com
This should be able to repeat. Also on Saturday and Sunday the company is not open, so on mondays it should look back on friday, and so forth, also accounting for public holidays.
Any help with this would be a life saver? I don't mind if you want to change the file names so that this issue with holidays can be addressed. However, somewhere a time stamp needs to be placed for the files.
You might want to check out the Dictionary object, it would probably help in this task. If you have any questions along the way ask another question. Not sure if someone else would want to give you a more thorough answer to this question.
Your project might be big enough that you would want to work with classes too.
Please avoid every Select in your code.
For instance,
Range("A1:D1").Select
Selection.AutoFilter
can be replaced by:
Range("A1:D1").AutoFilter