I've looked all over and found nothing. What I'm doing is showing one table using a sort/filter function in another sheet. I've simplified my formulas for your viewing pleasure, which are as follows:
=SORT(FILTER(A2:J23,
(C2:C23<>L2)+(D2:D23*M2),
(C2:C23<>L3)+(D2:D23*M3),
(C2:C23<>L4)+(D2:D23*M4),
(C2:C23<>L5)+(D2:D23*M5),
(C2:C23<>L6)+(D2:D23*M6),
(C2:C23<>L7)+(D2:D23*M7)),
A29, TRUE,
B29, FALSE,
C29, FALSE,
D29, FALSE,
E29, FALSE,
F29, FALSE,
G29, FALSE,
H29, FALSE,
I29, FALSE,
J29, FALSE)
The goal is simple. I want to simplify them, perhaps by using a range. They're the exact same formulas using one ascending variable.
If it helps, this is what it's doing:
(C2:C23<>L#) checks if col C equals a "type" in col L.
(D2:D23*M#) column M contains check boxes (True/False). Multiply that by arbitrary positive numbers in col D to get array of numbers to OR with first part.
Together, these formulas say, "If type matches, and button is unchecked, don't show row". Boolean logic is A+B' or (A'B)'.
In the sort part, there is a row of check boxes A29:J29 (1/0, 2/0, 3/0, ...). When pressed, the table is sorted by that column, A-Z in col A, and largest first Cols B-J.
EDIT: I've made a mock sheet to better illustrate what's going on, and updated the code to match this sheet. It can be found here: https://docs.google.com/spreadsheets/d/1cOre8sVOb3TE2OsaNC823UB18DAMO4pD4-mZqJtxu0k/edit?usp=sharing
Here is the formula:
=QUERY(
A2:J23,
"SELECT * "
& "WHERE C is not null "
& IF(COUNTIF(M29:M34, False) = 0, "", "AND NOT C MATCHES '" & JOIN("|", IFNA(FILTER(L29:L34, M29:M34 = False))) & "' ")
& IF(COUNTIF(A29:J29, ">0") = 0, "", "ORDER BY " & JOIN(", ", IFNA(FILTER(REGEXEXTRACT(ADDRESS(29, COLUMN(A29:J29), 4), "^\D+") & IF((COLUMN(A29:J29) = 1) + (COLUMN(A29:J29) = 3), "", " DESC"), A29:J29)))),
0
)
This one is a bit different than your previous question, because column letters must be used instead of ColN. More on that here.
And I made 3rd column sorted asc if checked because it is of a string type.
Related
I have a complicated sorting that I want, and I'm just not sure how to get power query to do it. The TLDR version is "oldest new ones first, then newest old ones." So I want to split the sort between ascending/descending depending on what data are in the columns.
Certain columns on my sheet (I through K) contain the word 'Yes' if it is a new item, otherwise blank. Possible combinations of columns that have 'yes' in them:
I only, J only, K only, I + J, J + K, I + J + K
Here's the sort logic I want:
All rows with a Yes in K are listed first, ascending by date (column H), whether they have 'Yes' in columns I or J or not.
Then, Of only the rows that are left, all rows with a Yes in J, ascending by date (column H)
Next, Of only the rows that are left, all rows with a Yes in I, ascending by date (column H)
Finally, the only rows left should not have a Yes in any columns I-K. Of those rows, DEscending by date (Column H).
I can sort of maybe figure out how to do the sort up through step 3 by creating a custom column to label and identifying whether the row will go in the first, second, or third sort, then sorting by that custom column before sorting the others.
But step 4 is stumping me because of the reverse to descending instead of ascending. I'm thinking maybe grouping the data, sorting it within the group descending and outside the group ascending (as a 4th entry in the custom column that sorted the first 3), and then expanding it back out again after the external sort, or something?
Please help!
Currently I'm only able to sort the sheet ascending and can't sort part of it descending.
Filter a column, then sort it. Filter another column and sort it. etc. Put them together
Load your data into powerquery (data ... from table/range ... )and use code below pasted into home ... advanced editor.... It assumes your data is loaded as Table1 with column headers A,H,I,J,K, so change that to reflect your actual table name and column names. If you have your own code, remove the first row and change the Source in the second row to reflect your #"PriorStepName"
sample code to transform image below on left to image on right:
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"A", Int64.Type}, {"H", type date}, {"I", type text}, {"J", type text}, {"K", type text}}),
Part1 = Table.Sort(Table.SelectRows(#"Changed Type", each ([K] = "Yes")),{{"H", Order.Ascending}}),
Part2 = Table.Sort(Table.SelectRows(#"Changed Type", each ([K] <> "Yes" and [J] = "Yes")),{{"H", Order.Ascending}}),
Part3 = Table.Sort(Table.SelectRows(#"Changed Type", each ([K] <> "Yes" and [J] <> "Yes" and [I] = "Yes")),{{"H", Order.Ascending}}),
Part4 = Table.Sort(Table.SelectRows(#"Changed Type", each ([K] <> "Yes" and [J] <> "Yes" and [I] <> "Yes")),{{"H", Order.Descending}}),
Combined = Table.Combine({Part1,Part2,Part3,Part4})
in Combined
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.
=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.
I'm using
DoCmd.SetOrderBy
for sorting a form by a specific field. But right now it sorts ascending or descending if I use DESC keyword. How can I do a check to see what sorting is active and do the opposite? If that field is ordered ascending and I click the button, the order become descending and vice versa.
You can get the current sort order by doing in the form code
debug.print me.orderby
It will come out something like
[FORM].[COLUMN] Desc
So then do an if statement
if me.orderby = [FORM].[COLUMN] Desc then
docmd.setorderby "[COLUMN] ASC"
else
docmd.setorderby "[COLUMN] Desc"
end if
Try that out. Changing the FORM and COLUMN to match yours of course
As #Sam suggested, check the value of the Me.OrderBy property to decide whether you want ascending or descending for the new sort order.
The following code sample assumes you want an ascending sort if there is no current sort (i.e. Me.OrderBy is an empty string).
Otherwise check whether Me.OrderBy is Like "* DESC". Note, if the current sort order is ascending, don't assume ASC will be present in Me.OrderBy. And don't assume the column name piece of Me.OrderBy will be present as [FORM].[COLUMN].
Dim strOrderBy As String
Dim strDirection As String
strOrderBy = Me.OrderBy
If Len(strOrderBy) = 0 Then
strDirection = "ASC"
Else
If strOrderBy Like "* DESC" Then
strDirection = "ASC"
Else
strDirection = "DESC"
End If ' Like
End If ' Len(strOrderBy)
DoCmd.SetOrderBy "[YourColumnName] " & strDirection