Skip to content

Commit 1fa2fc1

Browse files
Merge pull request taozhi8833998#2610 from taozhi8833998/fix-struct-expr-bigquery
fix: struct expr with orderby and limit in bigquery
2 parents b0307c8 + 727e515 commit 1fa2fc1

File tree

3 files changed

+67
-6
lines changed

3 files changed

+67
-6
lines changed

pegjs/bigquery.pegjs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2201,13 +2201,15 @@ json_expr
22012201
}
22022202

22032203
struct_expr
2204-
= s:(struct_type / KW_STRUCT) __ LPAREN __ c:column_clause __ RPAREN {
2204+
= s:(struct_type / KW_STRUCT) __ LPAREN __ c:column_clause __ RPAREN __ o:order_by_clause? __ l:limit_clause? {
22052205
return {
22062206
definition: s,
22072207
expr_list: c,
22082208
type: 'struct',
22092209
keyword: s && 'struct',
2210-
parentheses: true
2210+
parentheses: true,
2211+
order_by: o,
2212+
limit: l
22112213
}
22122214
}
22132215

@@ -2598,6 +2600,7 @@ aggr_func_list
25982600
aggr_func
25992601
= aggr_fun_count
26002602
/ aggr_fun_smma
2603+
/ aggr_array_agg
26012604

26022605
aggr_fun_smma
26032606
= name:KW_SUM_MAX_MIN_AVG __ LPAREN __ e:additive_expr __ RPAREN __ bc:over_partition? {
@@ -2675,6 +2678,16 @@ count_arg
26752678
}
26762679
/ d:KW_DISTINCT? __ c:or_and_expr __ or:order_by_clause? { return { distinct: d, expr: c, orderby: or, ...getLocationObject() }; }
26772680

2681+
aggr_array_agg
2682+
= pre:(ident __ DOT)? __ name:(KW_ARRAY_AGG / KW_STRING_AGG) __ LPAREN __ arg:expr __ RPAREN {
2683+
// => { type: 'aggr_func'; args:count_arg; name: 'ARRAY_AGG' | 'STRING_AGG'; }
2684+
return {
2685+
type: 'aggr_func',
2686+
name: pre ? `${pre[0]}.${name}` : name,
2687+
args: arg,
2688+
};
2689+
}
2690+
26782691
star_expr
26792692
= "*" { return { type: 'star', value: '*' }; }
26802693

@@ -3089,6 +3102,8 @@ KW_CAST = "CAST"i !ident_start { return 'CAST' }
30893102
KW_SAFE_CAST = "SAFE_CAST"i !ident_start { return 'SAFE_CAST' }
30903103

30913104
KW_ARRAY = "ARRAY"i !ident_start { return 'ARRAY'; }
3105+
KW_ARRAY_AGG = "ARRAY_AGG"i !ident_start { return 'ARRAY_AGG'; }
3106+
KW_STRING_AGG = "STRING_AGG"i !ident_start { return 'STRING_AGG'; }
30923107
KW_BYTES = "BYTES"i !ident_start { return 'BYTES'; }
30933108
KW_BOOL = "BOOL"i !ident_start { return 'BOOL'; }
30943109
KW_CHAR = "CHAR"i !ident_start { return 'CHAR'; }

src/array-struct.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { columnsToSQL } from './column'
2-
import { exprToSQL } from './expr'
2+
import { exprToSQL, orderOrPartitionByToSQL } from './expr'
3+
import { limitToSQL } from './limit'
34
import { arrayStructTypeToSQL, hasVal, toUpper } from './util'
45

56
function arrayExprListToSQL(expr) {
@@ -32,13 +33,13 @@ function arrayStructValueToSQL(expr) {
3233
}
3334

3435
function arrayStructExprToSQL(expr) {
35-
const { definition, keyword } = expr
36+
const { definition, keyword, orderby, limit } = expr
3637
const result = [toUpper(keyword)]
3738
if (definition && typeof definition === 'object') {
3839
result.length = 0
3940
result.push(arrayStructTypeToSQL(definition))
4041
}
41-
result.push(arrayStructValueToSQL(expr))
42+
result.push(arrayStructValueToSQL(expr), orderOrPartitionByToSQL(orderby, 'order by'), limitToSQL(limit))
4243
return result.filter(hasVal).join('')
4344
}
4445

test/bigquery.spec.js

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -897,7 +897,52 @@ describe('BigQuery', () => {
897897
'SELECT COUNT(*) FROM `bigquery-public-data.blah.events_*`',
898898
'SELECT COUNT(*) FROM `bigquery-public-data.blah.events_*`'
899899
]
900-
}
900+
},
901+
{
902+
title: 'struct expr',
903+
sql: [
904+
`WITH thingie AS (
905+
SELECT
906+
thingie2,
907+
thingie3,
908+
COUNT(*) as thingie4
909+
FROM thingie5.thingie6
910+
WHERE thingie7 BETWEEN '2025-10-24' AND '2025-10-30'
911+
AND thingie8 = TRUE
912+
AND thingie2 IS NOT NULL
913+
GROUP BY thingie2, thingie3
914+
),
915+
path_totals AS (
916+
SELECT
917+
thingie2,
918+
SUM(thingie4) as thingie9
919+
FROM thingie
920+
GROUP BY thingie2
921+
),
922+
thingie13 AS (
923+
SELECT SUM(thingie9) as overall_total
924+
FROM path_totals
925+
),
926+
thingie10 AS (
927+
SELECT
928+
thingie2,
929+
ARRAY_AGG(STRUCT(thingie3, thingie4) ORDER BY thingie4 DESC LIMIT 3) as thingie11
930+
FROM thingie
931+
GROUP BY thingie2
932+
)
933+
SELECT
934+
pt.thingie2,
935+
pt.thingie9 as thingie4,
936+
ROUND(100.0 * pt.thingie9 / tar.overall_total, 2) as thingie12,
937+
tc.thingie11
938+
FROM path_totals pt
939+
CROSS JOIN thingie13 tar
940+
JOIN thingie10 tc ON pt.thingie2 = tc.thingie2
941+
ORDER BY pt.thingie9 DESC
942+
LIMIT 20`,
943+
"WITH thingie AS (SELECT thingie2, thingie3, COUNT(*) AS thingie4 FROM thingie5.thingie6 WHERE thingie7 BETWEEN '2025-10-24' AND '2025-10-30' AND thingie8 = TRUE AND thingie2 IS NOT NULL GROUP BY thingie2, thingie3), path_totals AS (SELECT thingie2, SUM(thingie4) AS thingie9 FROM thingie GROUP BY thingie2), thingie13 AS (SELECT SUM(thingie9) AS overall_total FROM path_totals), thingie10 AS (SELECT thingie2, ARRAY_AGG(undefined) AS thingie11 FROM thingie GROUP BY thingie2) SELECT pt.thingie2, pt.thingie9 AS thingie4, ROUND(100.0 * pt.thingie9 / tar.overall_total, 2) AS thingie12, tc.thingie11 FROM path_totals AS pt CROSS JOIN thingie13 AS tar JOIN thingie10 AS tc ON pt.thingie2 = tc.thingie2 ORDER BY pt.thingie9 DESC LIMIT 20"
944+
]
945+
},
901946
]
902947

903948
SQL_LIST.forEach(sqlInfo => {

0 commit comments

Comments
 (0)