qSQL · Grouping & Aggregation · Practice Question
fby: Select First,Last and Second Last Rows by Group
Select First,Last and Second Last Rows by Group
Question
Given the following table:
t:([] sym:`a`b`b`b`c`c`c`c;
p:1 2 3 4 5 6 7 8)Result:
sym p
-----
a 1
b 2
b 3
b 4
c 5
c 6
c 7
c 8Using fby, write queries to return:
- The first row for each
sym - The last row for each
sym - The second-last row for each
sym
Solution
First row by symbol
select from t where i=(first;i) fby symResult:
sym p
-----
a 1
b 2
c 5Last row by symbol
select from t where i=(last;i) fby symResult:
sym p
-----
a 1
b 4
c 8Second-last row by symbol
select from t where i=({first -2#x};i) fby symResult:
sym p
-----
a 1
b 3
c 7Alternative Solution
If a symbol only has one row and should not appear in the second-last result, return a null index for groups of length 1:
select from t where i=({$[1=count x;0N;first -2#x]};i) fby symResult:
sym p
-----
b 3
c 7Explanation
The implicit column i represents the row index of each row in the table.
For the table t, the row indices are (shown as an extra column for illustration):
i sym p
-------
0 a 1
1 b 2
2 b 3
3 b 4
4 c 5
5 c 6
6 c 7
7 c 8The fby operator applies a function within each group and broadcasts the result back to the original rows.
First Row by Symbol
(first;i) fby symreturns, for every row, the first row index of that row's sym group:
0 1 1 1 4 4 4 4Comparing this with i:
i=(first;i) fby symproduces:
10001000bso the query:
select from t where i=(first;i) fby symreturns:
sym p
-----
a 1
b 2
c 5Last Row by Symbol
(last;i) fby symreturns, for every row, the last row index of that row's sym group:
0 3 3 3 7 7 7 7So:
select from t where i=(last;i) fby symreturns:
sym p
-----
a 1
b 4
c 8Second-Last Row by Symbol
The expression:
{first -2#x}takes the last two row indices from each group and returns the first of those two.
For example, for symbol b, the row indices are:
1 2 3Applying:
-2#1 2 3returns:
2 3and:
first 2 3returns:
2That is the row index of the second-last row for symbol b.
So:
select from t where i=({first -2#x};i) fby symreturns:
sym p
-----
a 1
b 3
c 7For symbol a, there is only one row. Since:
-2#0returns:
0 0the expression still returns row 0.
Excluding Groups with Only One Row
If a group with only one row should not be included in the second-last result, use:
{$[1=count x;0N;first -2#x]}This returns:
- a null (
0N) when the group has only one row, which never equals any row index - the second-last index otherwise
Therefore:
select from t where i=({$[1=count x;0N;first -2#x]};i) fby symreturns only:
sym p
-----
b 3
c 7Summary
Use fby with the implicit row index i when you want to select rows based on their position within each group:
select from t where i=(first;i) fby symselect from t where i=(last;i) fby symselect from t where i=({first -2#x};i) fby sym