=First(Fields!PrimeContractor.Value, "DataSet1") + ", " + Last(Fields!PrimeContractor.Value, "DataSet1")
This is good to get the first and last values from a field into one single cell, but how do I get everything else in between? I tried "Second" but that is a time value so I know that doesn't work.
You can use the LookupSet to get the selected values in a dataset then use JOIN to put them all together:
=Join(LookupSet(1, 1, Fields!PrimeContractor.Value, "DataSet1"), ", ")
Since you want all records, use 1 and 1 for the first two arguments (1 = 1). This reads as:
Lookup records where 1 = 1 and return the PrimeContractor in the DataSet1 Dataset.
Related
I am trying to invoke a function on an added column that will concatenate two columns. The catch is that I can't use the column name shorthand as I use dynamic parameters using strings to determine the column name.
Therefore the result is that I get a column as a List multiplied per row rather than the concatenated value for the specific row as intended
(func as text) =>
let
Source = Excel.CurrentWorkbook(){[Name="DataTBL"]}[Content],
\\This is the string extraction process for the parameter
funcTrig = Text.Start(func, 1),
columnA = "" & Text.BetweenDelimiters(func,"_","_") & "",
columnB = "" & Text.AfterDelimiter(func,"_",1) & "",
\\converting the string to column data
Convert2ColA = Table.Column(Source,columnA),
Convert2ColB = Table.Column(Source,columnB),
\\function to concatanate column A value at a specific row with column B value at the same row.
concat= StraightForward(Convert2ColA ,Convert2ColB)
in
concat
I have outlined with remarks the process and desired results, In the added picture I have pulled out the result of "Convert2ColA" what is the desired result will be 1999 in row one and so on.
I want to sort real-time when a number is calculated in a "Total" column, which is a sum based on other cells, inputted by the user. The sort should be descending and I did achieve this functionality using the following:
function onEdit(event){
var sheet = event.source.getActiveSheet();
var range = sheet.getDataRange();
var columnToSortBy = 6;
range.sort( { column : columnToSortBy, ascending: false } );
}
It's short and sweet, however empty cells in the total column which contain the following formula, blanking itself if the sum result is a zero, otherwise printing the result:
=IF(SUM(C2:E2)=0,"",SUM(C2:E2))
It causes these rows with an invisible formula to be included in the range selection and upon descending sort, they get slapped up top for some reason. I want these blank rows either sorted to the bottom, or in an ideal scenario removed from the range itself (Without deleting them and the formula they contain from the sheet) prior to sorting.
Or maybe some better way which doesn't require me dragging a formula across an entire column of mostly empty rows. I've currently resorted to adding the formula manually one by one as new entries come in, but I'd rather avoid this.
EDIT: Upon request find below a screenshot of the sheet. As per below image, the 6th column of total points needs to be sorted descending, with winner on top. This should have a pre-pasted formula running lengthwise which sums up the preceding columns for each participant.
The column preceding it (Points for Tiers) is automatically calculated by multiplying the "Tiers" column by 10 to get final points. This column could be eliminated and everything shifted once left, but it's nice to maintain a visual of the actual points awarded. User input is entered in the 3 white columns.
You want to sort the sheet by the column "F" as the descending order.
You want to sort the sheet by ignoring the empty cells in the column "F".
You want to move the empty rows to the bottom of row.
You don't want to change the formulas at the column "F".
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer?
Issue and workaround:
In the current stage, when the empty cells are scattered at the column "F", I think that the built-in method of "sort" of Class Range cannot be directly used. The empty cells are moved to the top of row like your issue. So in this answer, I would like to propose to use the sort method of JavaScript for this situation.
Modified script:
In order to run this function, please edit a cell.
function onEdit(event){
const columnToSortBy = 6; // Column "F"
const headerRow = 1; // 1st header is the header row.
const sheet = event.source.getActiveSheet();
const values = sheet.getRange(1 + headerRow, 1, sheet.getLastRow() - headerRow, sheet.getLastColumn())
.getValues()
.sort((a, b) => a[columnToSortBy - 1] > b[columnToSortBy - 1] ? -1 : 1)
.reduce((o, e) => {
o.a.push(e.splice(0, columnToSortBy - 1));
e.splice(0, 1);
if (e.length > 0) o.b.push(e);
return o;
}, {a: [], b: []});
sheet.getRange(1 + headerRow, 1, values.a.length, values.a[0].length).setValues(values.a);
if (values.b.length > 0) {
sheet.getRange(1 + headerRow, columnToSortBy + 1, values.b.length, values.b[0].length).setValues(values.b);
}
}
In this sample script, it supposes that the header row is the 1st row. If in your situation, no header row is used, please modify to const headerRow = 0;.
From your question, I couldn't understand about the columns except for the column "F". So in this sample script, all columns in the data range except for the column "F" is replaced by sorting. Please be careful this.
Note:
Please use this sample script with enabling V8.
References:
sort(sortSpecObj)
sort()
Added:
You want to sort the sheet by the column "F" as the descending order.
You want to sort the sheet by ignoring the empty cells in the column "F".
You want to move the empty rows to the bottom of row.
In your situation, there are the values in the column "A" to "F".
The formulas are included in not only the column "F", but also other columns.
You don't want to change the formulas.
You want to achieve this using Google Apps Script.
From your replying and updated question, I could understand like above. Try this sample script:
Sample script:
function onEdit(event){
const columnToSortBy = 6; // Column "F"
const headerRow = 1; // 1st header is the header row.
const sheet = event.source.getActiveSheet();
const range = sheet.getRange(1 + headerRow, 1, sheet.getLastRow() - headerRow, 6);
const formulas = range.getFormulas();
const values = range.getValues().sort((a, b) => a[columnToSortBy - 1] > b[columnToSortBy - 1] ? -1 : 1);
range.setValues(values.map((r, i) => r.map((c, j) => formulas[i][j] || c)));
}
A much simpler way to fix this is to just change
=IF(SUM(C2:E2)=0,"",SUM(C2:E2))
to
=IF(SUM(C2:E2)=0,,SUM(C2:E2))
The cells that are made blank when the sum is zero will then be treated as truly empty and they will be excluded from sort, so only cells with content will appear sorted at the top of the sheet.
Why your original formula doesn't work that way is because using "" actually causes the cell contain content so it's not treated as a blank cell anymore. You can test this by entering ISBLANK(F1) into another cell and check the difference between the two formulas.
I have some values like this,
tEn 1
teN 8
Ten 1
thrEE 2
tHRee 1
How do I add column 2 and generate this for all case-insensitive duplicates in column 1?
ten 10
three 3
I have tried using GROUP,
tmp = GROUP data BY (column1);
result = FOREACH tmp GENERATE
group,
SUM(data.column2) as count
But somehow it doesn't seem to give the right results. What do I do?
Strings are case sensitive. You need to make them all lower case first so that they match up
lowerdata = FOREACH data GENERATE LOWER(column1), column2;
and then do what you were doing before.
tmp = GROUP lowerdata BY (column1);
result = FOREACH tmp GENERATE
group,
SUM(data.column2) as count
I have the following report below i can get all the rows
SERVER NAME COUNT1 COUNT2 Count+% 7days count+% 30days
All Servers
( Server1,
Server2,
Server 3) 7 1,501 500 (20%) 850 (53.3%)
Server 1 2 705 200 (28.3%) 350 (49.6%)
Server 2 3 396 100 (25.2%) 200 (50.5%)
Server 3 2 400 200 (50%) 300 (75%)
I have done the last three rows, but how to get the top row? How can we sum up all the rows.In the top row as above?
the others are simple countDistint and count ,
For Count+ % students :
=Sum(IIf(Fields!Logged7Days.Value = "no", 1, 0)) &" ( "& FormatNumber((Sum(IIf(Fields!Logged7Days.Value = "no", 1, 0)) *100) / count(Fields!f_IdPupil.Value),2) & "%) "
And simply change column to 30days , for the next one basically they tell if the student was present in 7 days, 30 days time.
SAMPLE DATA:
Thank you
You can use your expression in any table/group header row; it will just be applied in that current scope, e.g. in a group header the aggregate will be applied to all rows in the group, and in a table header it will be applied to all rows in the dataset.
Say I have the following data:
I've created a simple report based on this:
You can see there are two table header rows, one with headings and one with data, and one group header row - the group is based on ServerName.
For the 7 Day Expression column both the fields in the table header row and the group header row have exactly the same expression:
=Sum(IIf(Fields!Logged7Days.Value = "no", 1, 0))
& " ( "
& FormatNumber((Sum(IIf(Fields!Logged7Days.Value = "no", 1, 0)) * 100)
/ count(Fields!f_IdPupil.Value),2) & "%) "
The is just your exact same expression with some minor formatting. A similar expression is applied in the 30 Day Expression column:
=Sum(IIf(Fields!Logged30Days.Value = "no", 1, 0))
& " ( "
& FormatNumber((Sum(IIf(Fields!Logged30Days.Value = "no", 1, 0)) * 100)
/ count(Fields!f_IdPupil.Value),2) & "%) "
You can see the results are as expected at both the group and grand total levels:
All this is to show that you just need to apply the same expression in the different scopes to get your results. If this doesn't look right to you; please let me know what results you expect based on my dataset.
I am trying to select some records using LINQ for Entities (EF4 Code First).
I have a table called Monitoring with a field called AnimalType which has values such as
"Lion,Tiger,Goat"
"Snake,Lion,Horse"
"Rattlesnake"
"Mountain Lion"
I want to pass in some values in a string array (animalValues) and have the rows returned from the Monitorings table where one or more values in the field AnimalType match the one or more values from the animalValues. The following code ALMOST works as I wanted but I've discovered a major flaw with the approach I've taken.
public IQueryable<Monitoring> GetMonitoringList(string[] animalValues)
{
var result = from m in db.Monitorings
where animalValues.Any(c => m.AnimalType.Contains(c))
select m;
return result;
}
To explain the problem, if I pass in animalValues = { "Lion", "Tiger" } I find that three rows are selected due to the fact that the 4th record "Mountain Lion" contains the word "Lion" which it regards as a match.
This isn't what I wanted to happen. I need "Lion" to only match "Lion" and not "Mountain Lion".
Another example is if I pass in "Snake" I get rows which include "Rattlesnake". I'm hoping somebody has a better bit of LINQ code that will allow for matches that match the exact comma delimited value and not just a part of it as in "Snake" matching "Rattlesnake".
This is a kind of hack that will do the work:
public IQueryable<Monitoring> GetMonitoringList(string[] animalValues)
{
var values = animalValues.Select(x => "," + x + ",");
var result = from m in db.Monitorings
where values.Any(c => ("," + m.AnimalType + ",").Contains(c))
select m;
return result;
}
This way, you will have
",Lion,Tiger,Goat,"
",Snake,Lion,Horse,"
",Rattlesnake,"
",Mountain Lion,"
And check for ",Lion," and "Mountain Lion" won't match.
It's dirty, I know.
Because the data in your field is comma delimited you really need to break those entries up individually. Since SQL doesn't really support a way to split strings, the option that I've come up with is to execute two queries.
The first query uses the code you started with to at least get you in the ballpark and minimize the amount of data you're retrieving. It converts it to a List<> to actually execute the query and bring the results into memory which will allow access to more extension methods like Split().
The second query uses the subset of data in memory and joins it with your database table to then pull out the exact matches:
public IQueryable<Monitoring> GetMonitoringList(string[] animalValues)
{
// execute a query that is greedy in its matches, but at least
// it's still only a subset of data. The ToList()
// brings the data into memory, so to speak
var subsetData = (from m in db.Monitorings
where animalValues.Any(c => m.AnimalType.Contains(c))
select m).ToList();
// given that subset of data in the List<>, join it against the DB again
// and get the exact matches this time
var result = from data in subsetData
join m in db.Monitorings on data.ID equals m.ID
where data.AnimalType.Split(',').Intersect(animalValues).Any ()
select m;
return result;
}