So I'm trying to sum a formula in visual studio crystal reports but only for the group level.
I have a one to many relationship of Contract to Ancillary_Charge. I'm trying to sum Contract.Cost, but also show each ancillary_charge. So I've set CONTRACT.ID as a group, and each ancillary charge as the detail.
The following is my formula for the ChargePrice
if ({#IsZero} or {#ShowPrice} = false) then 0 else {CONTRACT.CONTRACT_COST}
The formula for IsZero
({PAYMENT_TYPE.ID} = 1) and IsNull({CHARGE_STATUS.PAYMENT_STATUS});
The formula for ShowPrice figures out if it is at the group level and returns true or false
Global booleanvar thingy;
Global booleanvar otherthingy;
if (isNull({#Previous}) and thingy = false) then
thingy := true
else
thingy := false;
if otherthingy then
thingy := true;
otherthingy := false;
if (isNull({#Previous}) = false and next({CONTRACT.ID})<>{CONTRACT.ID}) then
otherthingy := true;
thingy
When I try to Sum ChargePrice, it tells me that "This field cannot be summarized".
Why? and else can I do what I'm trying to do, namely only add to the sum when
Instead of getting crystal to do the summation, do it yourself.
Create two extra formulas
fmlReset
Global NumberVar Total;
Total:=0;
fmlDisplay
Global NumberVar Total;
Total
Change your chargeprice formula to
Global NumberVar Total;
if ({#IsZero} or {#ShowPrice} = false) then
0;
else
Total:=Total+{CONTRACT.CONTRACT_COST};
Place fmlReset in your page report header or whenever you want to reset your total. Place fmlDisplay where you want to display the total.
Related
I have been trying several different ways to write an office script to search for a value in a cell and return the row or rows to power automate.
I believe I need to use range.find in order to make use of the "completematch: true" option.
However, I have also tried a filter and a foreach loop to find rows which include the text I am searching for.
I'm after a hint as to which method might be best?
essentially trying to:-
power automate - pass text parameter to the script
Scripts search for a match in excel business spreadsheet
the script finds match(s)
Script passes back the row(s) to powerautomate as an array
this is what I have so far: essentially it just finds the row number in which the matching result is found. This seems to work better to avoid partial matched (as happened with the filter method )
any pointers, most welcome
function main(workbook: ExcelScript.Workbook, siteNameToFilter: string) {
let activeSheet = workbook.getActiveWorksheet();
let range = activeSheet.getUsedRange();
let values = range.getValues();
/**
* This script searches for the next instance of the text "Fino" on the current worksheet.
*/
// Get the next cell that contains "Fino".
let findCell = range.find("Fino", {
completeMatch: true, /* Don't match if the cell text only contains "fino" as part of another string. */
matchCase: false,
searchDirection: ExcelScript.SearchDirection.forward /* Start at the beginning of the range and go to later columns and rows. */
});
// Set focus on the found cell.
findCell.select();
// Remove the "TK" text value from the cell, as well as any formatting that may have been added.
//tkCell.clear(ExcelScript.ClearApplyTo.all);
let row = findCell.getRow().getUsedRange();
let ur = findCell.getUsedRange();
console.log(row);
}
I think Find may only be returning the first match. It sounds like you want all matches with the siteName. To do this, you'd either want to filter the range or loop through it.
Here's an example that loops through the range and adds the values from the rows containing the site name to an array. After the loop's completed, the array containing the values is returning by the function:
function main(workbook: ExcelScript.Workbook, siteNameToFilter: string) {
let activeSheet = workbook.getActiveWorksheet();
let range = activeSheet.getUsedRange()
let values = range.getValues() as string[][];
let rowCount = range.getRowCount()
let colCount = range.getColumnCount()
let colIndex = range.getColumnIndex()
let rowsArr: string[][][] = []
for (let i = 0; i < rowCount; i++) {
for (let j = 0; j < colCount; j++) {
if (values[i][j] === siteNameToFilter) {
rowsArr.push(activeSheet.getRangeByIndexes(i, colIndex, 1, colCount).getValues() as string[][])
}
}
}
return rowsArr
}
EDIT - SOLVED
I have to make a rotation schedule for coworkers for the next year. Some coworkers have standard days off and I do not want to schedule them on those days.
This is the manual outcome I would like to get.
Example: Consultant A does not work on mondays, so I do not want Consultant A to be added to the schedule on a monday.
I then want consultant B to be added to the schedule as a fill-up. Consultant A would be next in line on a tuesday etc. Next would be consultant C but consultant C does not work on wednesdays. Therefore, we need to take consultant D for wednesday and consultant C on a thursday, and so on. When we are at the last consultant of the F column, it needs to start again at consultant A.
I have tried all kinds of formulas, like if statements and arrayformula. But there is no way that I know of to loop through the F column just with formulas.
I am not sure if this is at all clear what I want to achieve here, I am stuck đ
I am using additionally an add-on to send the schedule to everyone's agenda, thats also the reason why i'd love to automate this, because it would help me SO much.
I did try myself on some coding, but I am no coder and I am not sure if it would be helpful at all to share my failure đ But this is what I've tried so far:
function Loop() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var EndRow = ss.getLastRow();
for (var i = 2; i <= EndRow; i++) {
var Day = ss.getRange(i,2).getValue();
var Consultants = ss.getRange(i,6).getValue();
var Off = ss.getRange(i,7).getValue ();
var Count = ss.getRange(i,8).getValue();
if(Day == Off){
ss.getRange(i, 3).setValue(Consultants)
}else{
ss.getRange(i, 3).setValue(Consultants)
}
}
}
EDIT:
I found a way without using apps scripts, costs me some more work manually and first tried it with a shorter team list.
The highlighted yellow cells are the cells in which the day off was identical to the work-day cell. So they got switched.
I did have to copy paste my input list of consultants but if this is the only manual way, its fine :)
Try this:
Code:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName("Sheet1");
var dayCol = sh.getRange("B2:B343").getValues().flat(); //get day column values and convert it to 1d array
var dayOffCol = sh.getRange("G2:G9").getValues().flat(); //get day off values and convert it to 1d array
var dayOffColCopy; //initialize copy
var consCol = sh.getRange("F2:F9").getValues().flat(); //get consultants values or column F
var consColCopy; //initialize copy
var tempArray = []; //storage of final value for column C
for(var i = 0; i < dayCol.length; i++){ //loop through dayCol values
var ctr = (i % consCol.length); //used modulo as counter. the value will return to 0 if the value of i is divisible to the length of consCol or in example 8
//The if statement below will help up reset the value of
//consColCopy and dayOffColCopy once the values are emptied because of the splice()
if(ctr == 0){
consColCopy = consCol.slice();
dayOffColCopy = dayOffCol.slice();
}
//the loop below will get the first non-matching values of dayCol and dayOffColCopy,
//the first non-matching values will be removed to the copy variables using splice()
//and insert it to tempArray using push()
for(var j = 0; j < dayOffColCopy.length; j++){ //loop through dayOffColCopy values
if(dayCol[i] != dayOffColCopy[j]){
tempArray.push(consColCopy.splice(j, 1));
dayOffColCopy.splice(j, 1);
break; //exit loop
}
}
}
sh.getRange(2, 3, tempArray.length, 1).setValues(tempArray); //set the values of temp array to column C
}
Example Data & Output:
Note: Make sure to use the cell that has data in your range and change the sheet name. I also added comments in my code to explain the process.
References:
Array.prototype.push()
Array.prototype.slice()
Array.prototype.splice()
Class Range
I'm a beginner and wanna ask about While Loop Pseudocode for the number of loops if i want it to be entered by user and not specifying how many, should i write it like this? or i have to declare the SM first?
Thank you
BEGIN
Student = 0
WHILE Student < SM
Get Work Efficiency, Task Completion Effectiveness, Team Work, SM # SM is
the number of studentsâ marks to be entered
Sum = Work Efficiency + Task Completion Effectiveness + Team Work
Competency = (Sum / 50) * 100
If Competency >= 70%
grade = âAâ
display = âExceed Expectation!â
else if Competency >= 40% AND Competency < 70%
grade = âBâ
display = âMeet Expectationâ
else if Competency >= 0% AND Competency < 40%
grade = âCâ
display = âBelow Expectationâ
else
display = âInvalid inputâ
End if
Student = Student + 1
END WHILE
END
As you say, SM is provided by user's input, thus you should mention it somewhere. There is a lot of various ways of writing pseudocode and they mostly depend from your needs, so you could e.g. write:
SM <- integer user input
[rest of your code]
or wrap it in a function (that way you show that returned value is dependent from SM's value:
function foo(SM):
[rest of your code]
I want to do an event study and need some descriptives around the events I am testing with different window sizes.
Let's assume I have a data set with 10000 observations (stocks, dates, measures) and merge them with an announcement data set. Now, I want to get a dummy variable that is always 0 except for parameters given by me:
if date = announcement_date then;
window_dummy at t-60 to t-11 = 1
or
window_dummy at t-5 to t+5 = 1
I hope I described it appropriately and there is a way because there is no lead function or similar.
Best
M
From what I gather from this, you wish to have additional variable, which creates window (or binning) variable reaching x days to past and future;
First we generate some test data. SAS dates are just numbers so:
data begin;
do i = 21040 to 21080;
my_date= i;
output;
end;
drop i;
run;
Next we calculate the window:
%let act_date= 21060;
%let min_date= %eval(&act_date - 5); /*5 days to past*/
%let max_date= %eval(&act_date + 3); /*3 days to future*/
Then it's left to generate the dummy variable:
data refined;
set begin;
if &min_date <= my_date and
my_date <= &max_date then
dummy = 1;
else dummy = 0;
run;
Now, one can calculate this all in single datastep, but maybe this is more informative way.
Edit: you can specify windows as you please. In your case you could have:
min_date1= %eval(&act_date - 60);
max_date2= %eval(&act_date - 11);
....
Then just add them to the if clause with or operator.
I am a student learning how to use Pig script using the hortonworks sandbox. My problem is that I am not able to use the SUM function properly. I have successfully separated the fields of a firewall log and I am able to do perform several queries and use the count function... but no luck with the SUM function which I really need in one case. This code I used below:
A = FOREACH logs_base GENERATE device_id,src,src_port,dst,dst_port,tran_ip,tran_port,service,duration,sent,rcvd,sent_pkt,rcvd_pkt,SN,user,group1, REGEX_EXTRACT(date, '\\d{3}-(\\d{2})-\\d{2}', 1) AS(month:chararray);
F1 = FILTER A BY user == 'PR11MS1120' and month == '10';
grpd1 = group F1 by user;
counter = foreach grpd1 {
sum1 = SUM(A.rcvd);
sum2 = SUM(A.sent);
generate sum1, sum2;
};
dump counter;
C = foreach F1 generate rcvd, sent;
dump C;
When I dump just the variable C I get a result displaying many records indicating the amount of data received/sent for the filter applied. eg:
(223,123)
(334,444)
(21,12344)
(...,...)
All I really want to do is add all those records together and show that total amount of received and sent: (?,?).
Note: I have tried changing the variable type to int, long, and chararray with no success either.
Some of the errors I am getting while trying to solve this are:
Could not infer the matching function for org.apache.pig.builtin.SUM as multiple or none of them fit. Please use an explicit cast.
First make sure that the fields that you are summing up are of type int
Use - DESCRIBE A; to check the data type
After that, I think since you have used filter condition and then used group by on F1 -
F1 = FILTER A BY user == 'PR11MS1120' and month == '10';
grpd1 = group F1 by user;
So, while summing up you should use F1 instead of A -
counter = foreach grpd1 {
sum1 = SUM(F1.rcvd);
sum2 = SUM(F1.sent);
generate sum1, sum2;
};
Use DESCRIBE grpd1; and you will understand what I am trying to say, there will be no 'A'
I guess this should solve the error. Finally, check the logic of what you want in the result I have not checked that. Hope this helps.
PS - I am also a student and new to PIG.
A lucky guess here, I'm new to Pig too :)
I'm not sure if SUM can be casted to chararray(that would explain the error), so make rcvd and sent type:int and then generate the 2 sums for grpd1 bag:
F1 = FILTER A BY user == 'PR11MS1120' and month == '10';
grpd1 = group F1 by user;
C1 = foreach grpd1 generate SUM(F1.rcvd);
dump C1;
C2 = foreach grpd1 generate SUM(F1.sent);
dump C2;
NOTE: More info here.
Hope I helped a little!
Please try the following
A = FOREACH logs_base GENERATE device_id,src,src_port,dst,dst_port,tran_ip,tran_port,service,duration,sent,rcvd,sent_pkt,rcvd_pkt,SN,user,group1, REGEX_EXTRACT(date, '\\d{3}-(\\d{2})-\\d{2}', 1) AS(month:chararray);
F1 = FILTER A BY user == 'PR11MS1120' and month == '10';
grpd1 = group F1 by user;
C = foreach F1 generate group,SUM(F1.rcvd), SUM(F1.sent);
dump C;