aggregate functions in predicates

This commit is contained in:
jackfoxy 2022-10-21 10:44:14 -07:00
parent a84a0a201d
commit 231bac46a7
4 changed files with 69 additions and 22 deletions

View File

@ -89,8 +89,8 @@ SELECT [ TOP <n> ] [ BOTTOM <n> ] [ DISTINCT ]
```
`<column> ::=
{ [ { <alias>. | <table-view>. } ]<column-name>
| <constant>
| <column-alias> }
| <column-alias>
| <constant> }
```
Discussion:

View File

@ -1,4 +1,5 @@
/- ast
!:
|_ current-database=@t :: (parse:parse(current-database '<db>') "<script>")
::
:: generic urQL command
@ -54,7 +55,7 @@
is-clustered=?
columns=(list ordered-column:ast)
==
+$ expression ?(qualified-column:ast value-literal:ast value-literal-list:ast)
+$ expression ?(qualified-column:ast value-literal:ast value-literal-list:ast aggregate:ast)
+$ list6
$:
%list6
@ -413,6 +414,11 @@
;~(pose ;~(pfix whitespace parse-qualified-column) parse-qualified-column)
;~(pose ;~(pfix whitespace parse-value-literal) parse-value-literal)
==
++ cook-aggregate
|= parsed=*
(aggregate:ast %aggregate -.parsed +.parsed)
++ parse-aggregate ~+
(cook cook-aggregate ;~(plug ;~(sfix parse-alias pal) ;~(sfix get-datum par)))
::
:: indices
::
@ -831,7 +837,8 @@
;~(plug whitespace (jester 'outer'))
;~(plug whitespace (jester 'then'))
==
++ predicate-part ;~ pose ::
++ predicate-part ;~ pose
parse-aggregate
value-literal-list
;~(pose ;~(pfix whitespace parse-operator) parse-operator)
parse-datum
@ -916,7 +923,7 @@
(cold %ket ket)
parse-datum
==
++ parse-coalesce ~+ (more com get-datum)
++ parse-coalesce ~+ (more com ;~(pose parse-aggregate get-datum))
++ parse-math ;~ plug
(cold %begin (jester 'begin'))
(star scalar-token)
@ -953,15 +960,12 @@
;~(plug whitespace (jester 'divided'))
mic
==
++ parse-aggregate ~+ ;~ pose
(stag %selected-aggregate ;~(plug ;~(sfix parse-alias pal) ;~(sfix ;~(pose parse-qualified-column get-datum) ;~(plug whitespace par))))
(stag %selected-aggregate ;~(plug ;~(sfix parse-alias pal) ;~(sfix ;~(pose parse-qualified-column get-datum) par)))
==
++ parse-aggregate-column ~+ (stag %selected-aggregate parse-aggregate)
++ parse-alias-all ~+ (stag %all-columns ;~(sfix parse-alias ;~(plug dot tar)))
++ parse-object-all ~+ (stag %all-columns ;~(sfix parse-qualified-object ;~(plug dot tar)))
++ parse-selection ;~ pose
;~(plug ;~(sfix parse-aggregate whitespace) (cold %as (jester 'as')) ;~(pfix whitespace alias))
parse-aggregate
++ parse-selection ~+ ;~ pose
;~(plug ;~(sfix parse-aggregate-column whitespace) (cold %as (jester 'as')) ;~(pfix whitespace alias))
parse-aggregate-column
parse-alias-all
parse-object-all
;~(plug ;~(sfix ;~(pose parse-qualified-column parse-value-literal) whitespace) (cold %as (jester 'as')) ;~(pfix whitespace alias))

View File

@ -77,7 +77,7 @@
+$ binary-operator ?(%eq inequality-operator %distinct %not-distinct %in all-any-operator)
+$ unary-operator ?(%not %exists)
+$ conjunction ?(%and %or)
+$ predicate-component ?(ternary-operator binary-operator unary-operator conjunction qualified-column value-literal value-literal-list)
+$ predicate-component ?(ternary-operator binary-operator unary-operator conjunction qualified-column value-literal value-literal-list aggregate)
+$ predicate * :: would like to be (tree predicate-component), but type system does not support
+$ datum $%(qualified-column value-literal)
+$ datum-or-scalar $@(datum scalar-function)
@ -144,11 +144,16 @@
joins=(list joined-object)
==
+$ aggregate-source $%(qualified-column selected-scalar)
+$ aggregate
$:
%aggregate
function=@t
source=* :: should be aggregate-source
==
+$ selected-aggregate
$:
%selected-aggregate
source=aggregate-source
aggregate-function=@t
aggregate=aggregate
alias=(unit @t)
==
+$ selected-column $%(%all qualified-column selected-scalar selected-object selected-aggregate)

View File

@ -930,6 +930,8 @@
++ t2-bar [[%qualified-column [%qualified-object ~zod 'UNKNOWN' 'COLUMN' 'T2'] 'bar' ~] ~ ~]
++ foobar [[%qualified-column [%qualified-object ~zod 'UNKNOWN' 'COLUMN-OR-CTE' 'foobar'] 'foobar' ~] ~ ~]
++ value-literal-list [[%value-literal-list %ud '3;2;1'] ~ ~]
++ aggregate-count-foo [%aggregate %count %qualified-column [%qualified-object 0 'UNKNOWN' 'COLUMN-OR-CTE' %foo] %foo 0]
++ literal-10 [[%ud 10] 0 0]
::
:: re-used simple predicates
++ foobar-gte-foo [%gte foobar foo]
@ -1128,21 +1130,43 @@
" AND (T1.foo3< any (1,2,3) OR T1.foo2=~zod AND foo=1 )) "
%+ expect-eq
!> king-and
!> (wonk (parse-predicate:parse [[1 1] predicate]))
::
:: aggregate inequality
++ test-predicate-31
=/ predicate " count( foo ) > 10 "
%+ expect-eq
!> [%gt [aggregate-count-foo 0 0] literal-10]
!> (wonk (parse-predicate:parse [[1 1] predicate]))
::
:: aggregate inequality, no whitespace
++ test-predicate-32
=/ predicate "count(foo) > 10"
%+ expect-eq
!> [%gt [aggregate-count-foo 0 0] literal-10]
!> (wonk (parse-predicate:parse [[1 1] predicate]))
::
:: aggregate equality
++ test-predicate-33
=/ predicate "bar = count(foo)"
%+ expect-eq
!> [%eq bar [aggregate-count-foo 0 0]]
!> (wonk (parse-predicate:parse [[1 1] predicate]))
::
:: scalar
::
++ column-foo [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='foo'] column='foo' alias=~]
++ column-foo2 [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='foo2'] column='foo2' alias=~]
++ column-foo3 [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='foo3'] column='foo3' alias=~]
++ column-bar [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='bar'] column='bar' alias=~]
++ litteral-zod [value-type=%p value=0]
++ litteral-1 [value-type=%ud value=1]
++ naked-coalesce ~[%coalesce column-bar litteral-zod litteral-1 column-foo]
++ literal-zod [value-type=%p value=0]
++ literal-1 [value-type=%ud value=1]
++ naked-coalesce ~[%coalesce column-bar literal-zod literal-1 column-foo]
++ simple-coalesce [%scalar %foobar naked-coalesce]
++ simple-if-naked [%if [%eq [litteral-1 0 0] litteral-1 0 0] %then column-foo %else column-bar %endif]
++ simple-if-naked [%if [%eq [literal-1 0 0] literal-1 0 0] %then column-foo %else column-bar %endif]
++ simple-if [%scalar %foobar simple-if-naked]
++ case-predicate [%when [%eq [litteral-1 0 0] litteral-1 0 0] %then column-foo]
++ case-predicate [%when [%eq [literal-1 0 0] literal-1 0 0] %then column-foo]
++ case-datum [%when column-foo2 %then column-foo]
++ case-coalesce [%when column-foo3 %then naked-coalesce]
++ case-1 [%scalar %foobar [%case column-foo3 ~[case-predicate] %else column-bar %end]]
@ -1219,12 +1243,26 @@
!> case-5
!> (wonk (parse-scalar:parse [[1 1] scalar]))
::
:: if aggragate
++ test-scalar-10
=/ scalar "SCALAR foobar IF count(foo)=1 THEN foo3 else bar ENDIF"
%+ expect-eq
!> [%scalar %foobar [%if [%eq [aggregate-count-foo 0 0] literal-1 0 0] %then column-foo3 %else column-bar %endif]]
!> (wonk (parse-scalar:parse [[1 1] scalar]))
::
:: coalesce aggragate
++ test-scalar-11
=/ scalar "SCALAR foobar AS COALESCE count(foo),~zod,1,foo"
%+ expect-eq
!> [%scalar %foobar ~[%coalesce aggregate-count-foo literal-zod literal-1 column-foo]]
!> (wonk (parse-scalar:parse [[1 1] scalar]))
::
:: select
::
++ simple-columns ~[[%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='x1'] column='x1' alias=~] [%qualified-column qualifier=[%qualified-object ship=~ database='db' namespace='ns' name='table'] column='col1' alias=~] [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN' name='table-alias'] column='name' alias=~] [%qualified-column qualifier=[%qualified-object ship=~ database='db' namespace='dbo' name='table'] column='col2' alias=~] [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN' name='T1'] column='foo' alias=~] [%ud 1] [%p 0] [%t 'cord']]
++ aliased-columns-1 ~[[[%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='x1'] column='x1' alias=~] %as %foo] [[%qualified-column qualifier=[%qualified-object ship=~ database='db' namespace='ns' name='table'] column='col1' alias=~] %as %foo2] [[%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN' name='table-alias'] column='name' alias=~] %as %bar] [[%qualified-column qualifier=[%qualified-object ship=~ database='db' namespace='dbo' name='table'] column='col2' alias=~] %as %bar2] [[%ud 1] %as %foobar] [[%p 0] %as 'F1'] [[%t 'cord'] %as 'BAR3']]
++ mixed-all ~[[%all-columns %qualified-object ship=~ database='db' namespace='dbo' name='t1'] [[%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='foo'] column='foo' alias=~] %as 125.762.588.864.358] [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='bar'] column='bar' alias=~] %all [%all-columns 'T2']]
++ aggregates ~[[%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='foo'] column='foo' alias=~] [[%selected-aggregate 'COUNT' [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='foo'] column='foo' alias=~]] %as 'CountFoo'] [%selected-aggregate 'cOUNT' [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='bar'] column='bar' alias=~]] [%selected-aggregate 'sum' [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='bar'] column='bar' alias=~]] [[%selected-aggregate 'sum' [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='foobar'] column='foobar' alias=~]] %as 'foobar']]
++ aggregates ~[[%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='foo'] column='foo' alias=~] [[%selected-aggregate %aggregate function='COUNT' source=[%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='foo'] column='foo' alias=~]] %as 'CountFoo'] [%selected-aggregate %aggregate function='cOUNT' source=[%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='bar'] column='bar' alias=~]] [%selected-aggregate %aggregate function='sum' source=[%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='bar'] column='bar' alias=~]] [[%selected-aggregate %aggregate function='sum' source=[%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='foobar'] column='foobar' alias=~]] %as 'foobar']]
::
:: star select top, bottom, distinct, trailing whitespace
++ test-select-01
@ -1471,8 +1509,8 @@
%+ expect-eq
!> [%select [aggregates]]
!> (wonk (parse-select:parse [[1 1] select]))
:: for later inclusion in full query
:: for later inclusion in full query
::
:: fail top, bottom, distinct, no column selection
::++ test-fail-select-