Related
I have the following formula in the 'Available Staff' sheet:
=LET(AvailabilityCalc,FILTER(AllStaffProjectAllocationTbl, IF(ISBLANK($I$11),1,(AllStaffProjectAllocationTbl[Role]=$I$11))*IF(ISBLANK($I$8),1,(AllStaffProjectAllocationTbl[Employee]=$I$8))*IF(ISBLANK($I$14),1,(AllStaffProjectAllocationTbl[Discipline]=$I$14))* (AllStaffProjectAllocationTbl[End Date]<$I$2)*(TRANSPOSE(MMULT(SEQUENCE(1,ROWS(AllStaffProjectAllocationTbl),1,0),TRANSPOSE(AllStaffProjectAllocationTbl[End Date]>TRANSPOSE(AllStaffProjectAllocationTbl[End Date]))*(AllStaffProjectAllocationTbl[Employee]=TRANSPOSE(AllStaffProjectAllocationTbl[Employee]))*(1)))-MMULT((TRANSPOSE(AllStaffProjectAllocationTbl[Employee])=AllStaffProjectAllocationTbl[Employee])+0,SEQUENCE(ROWS(AllStaffProjectAllocationTbl),1,1,0))+1=0)),IFERROR(SORT(INDEX(AvailabilityCalc,SEQUENCE(ROWS(AvailabilityCalc)),{1,4,5,9}),4),""))
that sits in A2 and pulls in all staff that are available after a specific date defined in I2. This unfortunately has an issue as it pulls the data from the staff that have been allocated to a project previously from a 'Staff Project Allocation' sheet and doesn't incorporate the staff from the 'Staff Details' sheet that are yet to be allocated to a project.
The 'Staff Project Allocation' sheet :
The 'Staff Details' sheet :
Someone kindly helped me with the above function and I'm not sure how to modify it to do what I want. Could it be simpler to keep the above as is and create a new set of data to the right of it say, that pulls in the entries from the 'Staff Details' sheet that don't appear in the data created by the formula and are available from the date specified - whilst also being a development role, which I can do by checking their discipline against another table? Or is there a way to modifiy the formula above to incoporate the data? Something I also need to incorporate in the above function, which I overlooked originally, is to exclude any staff member that has had their employment terminated as noted in the Employment Status columns, so any suggestions on how to incoporate this too would be greatly appreciated.
I'm also starting to wonder whether a VBA solution maywell be a better approach, thoughts?
Edit 1
Adjusted function based on the suggestions from Max below. This now includes the ability to filter based on the employment status.
=LET(
staff, AllStaffProjectAllocationTbl,
employee, AllStaffProjectAllocationTbl[Employee],
role, AllStaffProjectAllocationTbl[Role],
discipline, AllStaffProjectAllocationTbl[Discipline],
endDate, AllStaffProjectAllocationTbl[End Date],
employmentStatus, AllStaffProjectAllocationTbl[Employment Status],
rowCt, ROWS(AllStaffProjectAllocationTbl),
roleSelection, $I$11,
employeeSelection, $I$8,
disciplineSelection, $I$14,
availableFromDate, $I$2,
empStatusSelection,"Employment Terminated",
mmult_1, MMULT(SEQUENCE(1,rowCt,1,0),TRANSPOSE(endDate>TRANSPOSE(endDate))*(employee=TRANSPOSE(employee))*(1)),
mmult_2, MMULT((TRANSPOSE(employee)= employee)+0,SEQUENCE(rowCt,1,1,0)),
roleCondition, IF(ISBLANK(roleSelection),1,(role=roleSelection)),
employeeCondition, IF(ISBLANK(employeeSelection),1,( employee=employeeSelection)),
disciplineCondition, IF(ISBLANK(disciplineSelection),1,(discipline=disciplineSelection)),
empStatusCondition, NOT(employmentStatus=empStatusSelection),
AvailabilityCalc,FILTER(staff,roleCondition*employeeCondition*disciplineCondition*empStatusCondition*(endDate<availableFromDate)*(TRANSPOSE(mmult_1)-mmult_2+1=0)),
IFERROR(SORT(INDEX(AvailabilityCalc,SEQUENCE(ROWS(AvailabilityCalc)),{1,4,5,10}),4),"")
)
Edit 2
I now have two tables, one from the Staff Details sheet, showing all staff who are development staff and still employed, this can be seen on the left in the following image (note this all staff allocated to a project or not) and defined by =FILTER(FILTER(StaffDetailsTbl,(StaffDetailsTbl[Employment Status]<>"Employment Terminated")*(StaffDetailsTbl[Dev Role]="Yes")),{1,1,1,0,0,0,1,0,0}), and a separate table defined by the Let function above in edit 1, showing all staff allocated to a project that are available based on a specified date, see table on the right.
I'd now like to merge the table on the left into the table on the right whilst also removing any duplicate entries. Would the most logical first step to be to adjust the filter for the left table to exclude entries that are in the right table? Then look to merge the two in to the right table somehow? Or is it possible to take the Filter defining the left most table and work it directly in to the function defining the right table?
Edit 3
The following function now filters out the entries from the StaffDetailsTbl Table that don't exist in the AllStaffProjectAllocationTbl Table:
=FILTER(FILTER(StaffDetailsTbl,(StaffDetailsTbl[Employment Status]<>"Employment Terminated")*(StaffDetailsTbl[Dev Role]="Yes")*(IF(ISERROR(VLOOKUP(StaffDetailsTbl[Employee], AllStaffProjectAllocationTbl, 1, FALSE)),1,0 ))),{1,1,1,0,0,0,1,0,0})
Giving the resulting table on the left for staff not allocated to a project and those allocated to a project and who are available after a specified date on the right:
I now need to figure out how to merge the filter formula from the left table in to the Let function above, or alternatively, build another table from the two that supports all the roleSelection, employeeSelection, disciplineSelection and availableFromDate functionality. Any thoughts on the best way I can do this please?
The formula logic is complex enough that it's unlikely someone here would be able to invest the time required to work through this on their own. It means someone has to "reverse engineer" the meaning of every reference, like "what does $I$11 really represent".
While not technically an answer, I can provide some help on how to simplify the problem, and then document the logic for your future reference. This won't meet the technical definition of a "proper" StackOverflow answer, but it's too much to fit in a comment and still better than leaving you empty-handed.
Use LET to simplify
You already have it, so let's go further with it, so we can simplify the formula as much as possible. Here's one example of using LET to further break down the formula, and using alt-Enter to create non-breaking returns in the excel formula:
=LET(
staff, AllStaffProjectAllocationTbl,
emp, AllStaffProjectAllocationTbl[Employee],
role, AllStaffProjectAllocationTbl[Role],
disc, AllStaffProjectAllocationTbl[Discipline],
endDate, AllStaffProjectAllocationTbl[End Date],
rowCt, ROWS(AllStaffProjectAllocationTbl),
mmult_1, MMULT(SEQUENCE(1,rowCt,1,0),TRANSPOSE(endDate>TRANSPOSE(endDate))*(emp=TRANSPOSE(emp))*(1)),
mmult_2, MMULT((TRANSPOSE(emp)=emp)+0,SEQUENCE(rowCt,1,1,0)),
roleCondition, IF(ISBLANK($I$11),1,(role=$I$11)),
empCondition, IF(ISBLANK($I$8),1,(emp=$I$8)),
discCondition, IF(ISBLANK($I$14),1,(disc=$I$14)),
AvailabilityCalc,FILTER(staff,roleCondition*empCondition*discCondition*(endDate<$I$2)*(TRANSPOSE(mmult_1)-mmult_2+1=0)),
IFERROR(SORT(INDEX(AvailabilityCalc,SEQUENCE(ROWS(AvailabilityCalc)),{1,4,5,9}),4),"")
)
This is still a lot to take in, but it separates the complexity of how we found/calculated the inputs from the actual Filter and Result logic at the end. if it was my sheet I'd go further and break the formulas down even more, like giving $I$8 or "transpose(emp)=emp+0" a name as well. The more granular, the better.
Then Document your LET formula right in excel
On another sheet, create an Excel table that documents the LET parameters:
Name
Equates to
Which means
disc
AllStaffProjectAllocationTbl[Discipline]
Discipline Col of Staff Table
roleCondition
IF(ISBLANK($I$11),1,(role=$I$11))
Role from I11, or 1 if I11 is blank
xyz
$I$11
describe what I11 is
I put "xyz" in row 3, but the point is to give a name to each thing, if you are not using name manager.
Hope this helps, either to add clarity for you, or to get someone else started creating a full answer.
I'm trying to rank some data in spotfire, and I'm having a bit of trouble writing a formula to calculate it. Here's a breakdown of what I am working with.
Group: the test group
SNP: what SNP I am looking at
Count: how many counts I get for the specific SNP
What I'd like to do is rank the average # of counts that are present for each SNP, within the group. Thus, I could then see, within a group, which SNP ranks #1, #2, etc.
Thanks!
TL;DR Disclaimer: You can do this, though if you are changing your cross table frequently, it may become a giant hassle. Make sure to double-check that logic is what you'd expect after any modification. Proceed with caution.
The basis of the Custom Expression you seem to be looking for is as follows:
Max(DenseRank(Count() OVER (Intersect([Group],[SNP])),"desc",[Group]))
This gives the total count of rows instead of the average; I was uncertain if "Count" was supposed to be a column or not. If you really do want to turn it into an average, make sure to adjust accordingly.
If all you have is the Group and the SNP nested on the left, you're done and good to go.
First issue, when you want to filter it down, it gives you the dense rank of only those in the filtered set. In some cases this is good, and what you're looking for; in others, it isn't. If you want it to hold fast to its value, regardless of filtering, you can use the same logic, but throw it in a Calculated column, instead of in the custom expression. Then, in your CrossTable Aggregation, get the max of the Calculated Column value.
Calculated Column:
DenseRank(Count() OVER (Intersect([Group],[SNP])),"desc",[Group])
Second Issue: You want to pivot by something other than Group and SNP. Perhaps, for example, by date? If you throw the Date across the top, it's going to show the same numbers for every month -- the overall numbers. This is not particularly helpful.
To a certain extent, Spotfire's Custom Expressions can handle this modification. If you switch between using a single column, you could use the following:
Max(DenseRank(Count() OVER (Intersect([${Axis.Columns.ShortDisplayName}],[Group],[SNP])),"desc",[Group],[${Axis.Columns.ShortDisplayName}]))
That would automatically pull in the column from the top, and show you the ranking for each individual process date.
However, if you start nesting, using hierarchies, renaming your columns, or having multiple aggregations and throwing (Column Names) across the top, you're going to start having to pay a great deal to your custom expression. You'll need to do some form of string replacement around the Axis.Column, or use expression instead of Short Names, and get rid of Nests, etc.
Any layer of complexity will require this sort of analysis, so if your end-users have access to modify the pivot table... honestly, I probably wouldn't give them this column.
Third Issue: I don't know if this is an issue, exactly, but you said "Average Counts" -- Average per day? Per Month? When averaging, you will need to decide if, for example, a month is the total number of days in month or the number of days that particular payor had data. However you decide to aggregate it, make sure you're doing it on the right level.
For the record, I liked the premise of this question; it's something I'd thought would be useful before, but never took the time to try to implement, since sorting a column or limiting a table to only show the top 10 values is much simpler
I am creating an attendance tracking form for work and require someone with more advanced knowledge of excel. This is to track employee tardy's and unplanned absences (UPT). When employees get too many tardy's or UPT's it is called an "Occurrence", when the number of occurrences increase it will increase the "Action Level". I input new data every 2 weeks and then send out emails to notify employees and their managers of increased action levels due to these attendance issues, I want this spreadsheet to do some of the work for me since I am working with hundreds of employees and so the process can sometimes take multiple days to complete.
My objective is to populate the Employee overview cells with the correct details from the Attendance Details page. The challenging part is that there are three rules that dictate which dates I need to populate the Employee Overview with.
Rule 1: Four tardies (TAR) makes an occurrence.
Rule 2: One UPT makes an occurrence, but if there can be multiple UPT's that only make one occurrence as long as they are within 5 days of each other.
Rule 3: Tardies and UPT's disappear after 365 days.
The increase of occurrences will increase the action level (See table in Employee Overview Screenshot).
In my example screenshots, the details should produce the hardcoded Employee overview I made for Bob Smith. I am not expecting anyone to have all the answers, but please help me by suggesting tips or tools available for accomplishing what I require. Please ask any clarifying questions if you wish to help but don't understand what I am requiring.
Screenshot of Attendance Details
Screenshot of Employee Overview for Bob Smith (Hardcoded)
I propose :
break the task/evaluation
Each rule may generate a set of new cell/data/table. thus, work with 1 rule first.
Repeat for another rule.
Consolidate.
these are just my head thinking out loud... hope it helps in anyways.. (care to comment? :)
Rule 1 : =if(countif(<TarRange>,"TAR")>=4,1,0) OR =countif(<TarRange>,"TAR")/4
Rule 2 : make a new list of "UPT"& its date, work from there. arranged the data by date, and use =if((day(<NextEntryDate>-day(<previousEntryDate>))<=5,<currentEntrydate>,"")
Rule 3 : every date cell values can be extracted using year(),month() and day(). Also look in to days calculation in excel help. I see that you'll need an extra column (beside the Rule 2 list) to do a moving summation. An example of moving summation is in the column H & I inside this post :
it uses if(<Day1>=<Day2>,<Count>,<DontCount>) Syntax. it can be change to year1/year2 in your case.
IMHO. Do share with us if you are stuck/successful. (:
A simplified version of my data would look like:
Own_Name Own_Position Year Boss_Name Boss_Position
John Director 2017 Tess Managing Director
Tess Lead Director 2017 Jim CEO
John Lead Director 2018 Jim CEO
Tess CFO 2018 Jim CEO
All data concerning Own_Name, Own_Position and Year is present (so Jim and any others would get their own rows with Own_Name and Boss_Name etc.), but there are many entries where the Boss_Position (but notBoss_Name`) is missing.
Thus, I'm trying to find what the Boss_Position will be, given the Boss_Name and Year. I can do this if I need to pull just one observation (just keep the relevant data where Own_Name matches Boss_Name and Year matches, and use the corresponding Own_Position), but I am not sure what the best way to do this would be where I'm looping through all the missing observations for Boss_Name, since using keep would seem to be very destructive and time consuming.
Ideally, the code would look something like
replace Boss_Position = Own_Position[YearNameMatcher(Boss_Name Year)] if missing(Boss_Position)
where YearNameMatcher is the function that does what I'm asking for, but I am not sure how to best proceed.
I'm also new to Stata, so I may not be aware of more obvious solutions, though I have tried searching without success.
One solution is to generate a separate and temporary dataset with the unique values of variables Boss_Name-Year and then merge this dataset with the original data. You can try this code with your data:
snapshot save
keep if Boss_Position!=""
drop Own*
duplicates drop Year Boss_name, force
tempfile boss
save `boss'
snapshot restore 1
drop Boss_Position
merge m:1 Boss_Name Year using `boss'
snapshot erase _all
This code supposes that the paired values Boss_name and Year are unique. With this approach you don't need to loop through all the missing observations.
I would like to be able to use today's date in a calculated column in a SharePoint list to, for example, determine whether a task is overdue. There is a well-documented trick that involves creating a dummy column named "Today," using it in a formula, and then deleting it, thereby "tricking" SharePoint into using the Today function.
The problem is that this method does not work reliably -- the calculation is not dynamic; it is only made when the item is saved, and therefore the Today "column" effectively becomes the Modified Date. (This is probably why SharePoint won't let you use the Today function in a straight-forward way.)
Has anyone found a solution that works? I know I can use javascript to get the actual date on the client side and display colors, flags, whatever, but I am looking for a "server side" solution.
For reference, the Today column trick and its problems are described fairly well at these two posts and associated comments:
http://blogs.msdn.com/cjohnson/archive/2006/03/16/552314.aspx and http://pathtosharepoint.wordpress.com/2008/08/14/calculated-columns-the-useless-today-trick/
There simply isn't a work around for this. As the values for the list are stored in the database and returned "as is" to other featurs such as the search crawler, a dynamic field cannot be created.
It is possible to create a custom field that will display the value using todays date in its calculation.
In addition to Christophe's (PathToSharePoint)'s article this also covers the Today trick and why it doesn't work
The Truth about using Today in calculated columns
There are a number of fudges, probably the best one is Dessie's console app (mentioned above by MNM)
Dynamically updating a SharePoint calculated column containing a Today reference
Its good but its not perfect, for example you may have to worry about different timezones.
Before going down this route you should ask yourself if you really, really need to do this. For example :-
If you want a countdown (days overdue/days left to complete a task) then you can use SPD and a XLST Data View web part
If you want a view to show overdue items or items created in the last X days ec then you can use [Today] in a views filter 2
If you create a Today column it needs to be updated. You can do that with either a timer job or by placing a jquery script on a page that is hit by the user. The script could call SPServices.SPUpdateMultipleListItems to do the update. Pass a CAML clause so that you only update the list items where the Today value needs to be updated, e.g. once per day.
My advice is to create your on field that does this calculation for you and then reference it in your SharePoint list. Not a simple implementation but it would work.
I have been looking for a solution either, still no luck.. The Today column trick has the limitation of not being dynamic.
I do have one suggestion though, why don't we create a timer job that will update a certain a certain column with the current date every day at 12 AM. I know some of you all might think it an over head. Just my suggestion :D!!
I came up with a very rough, but working solution to this problem without having to do any coding. I'll explain both how i made the today column and how i worked that in to an overdue column, becuase that column was a pain to find out how to do as well.
First, I made a column named "today" (gasp!). Next I made a column named "Days Overdue". I then opened up sharepoint designer and created a new workflow. I set it to run every time an item is edited/updated (keep in mind I turned off versioning for this list, otherwise I would have had to resort to coding to avoid a bunch of useless data building up on our server). I set the actions to simply store the modified date in a workflow variable, then change the value of the today column to that variable. although the modified column is a date/time and my today column is just a date, it transfers just fine. I then set the workflow to pause for 2 hours. you can set this to whatever amount of time you want obviously, it will just change the latest possible time for your today column to update, i.e. 2AM in my case.
on to the days overdue column. this is the code for that guy -
=IF([Due Date]>Today,"None",IF([Date Closed]=0,Today-[Due Date],IF([Due Date]>[Date Closed],"None",IF(Today>=[Date Closed],[Date Closed]-[Due Date],IF([Due Date]<Today,Today-[Due Date])))))
This shows the days overdue in number form in days, or if its not overdue, it shows "None". You can use either a number format or a string format, but NOT A DATE FORMAT. Well, I hope this helps anyone who is running into this problem and doesn't want to have to delve into coding.
EDIT: I forgot to say that in the code above for the days overdue column, I put in that if today is past the date closed, to use the date closed minus the due date instead of today minus due date, to ensure that the calculation doesnt keep occurring after an item has been closed. you probably would have noticed that in the code, but i felt i should point it out just in case.
EDIT 2: The code I had in before my 2nd edit for my calculated column didn't calculate the days overdue properly after an issue had been marked "closed." I put in the updated code. The last part of the code doesn't make sense, as it is the same logic as the beginning, but it worked so I didn't want to take any chances! :)
Peace.
I've used the following and had no problems.
Field Name: Overdue
Field Type: Calculated
Data Type Returned: Yes/No
Formula:
=AND([Due Date]<NOW(),Status<>"Completed",[Due Date]<>"")
Here is a workaround:
Create a date column called Today.
Use this column in your calculated formula (ignore the fact that the formula returns a wrong value).
After you are done with the formula, delete the Today column from your list.
For some reason it works this way! Now Sharepoint treats the Today in your formula as today's date.
Note: If you decide you want to change the formula, you have to create the Today column again. Otherwise, it wouldn't recognize Today as a valid column.
I Tried #Farzad's approach and it seems to be working perfectly. I wanted to do a custom count on Days Elapsed so added a calculated column which previously I was using a difference between the Created Date and Modified Date Columns, which was only showing up whenever a user updated the post, much to my dismay.
I now have a formula which works as I would want to and uses the Today column, and here it is for anyone who would like to use it. I also have a Status column on the basis of which a base of On Hold is used, and the remaining formula are based on the date difference of Today - Created.
=IF(Status="On Hold","On Hold",IF(AND(Today=Created,(DATEDIF(Created,Today,"D")=0)),"New",IF(AND(Today<>Created,(DATEDIF(Created,Today,"D")=0)),"New (updated)",IF(DATEDIF(Created,Today,"d")>3,"Need Update Immediately",IF(DATEDIF(Created,Today,"d")=1,"One day old",IF(DATEDIF(Created,Today,"d")=2,"Two days old",""))))))
Basically its just a bunch of nested IF conditions which get me labels on the basis of which I can add a group to my view and filter out data if needed. Hope this helps anyone looking for an answer!