Expressions and operators

PRQL allows expressions, like 2 + 3 or ((1 + x) * y) made up of various operators. In the example below, note the use of expressions to calculate the alias circumference and in the filter transform.

PRQL

1. from foo
2. select [
3. circumference = diameter * 3.14159,
4. color,
5. ]
6. filter circumference > 10 && color != "red"

SQL

1. WITH table_1 AS (
2. SELECT
3. diameter * 3.14159 AS circumference,
4. color
5. FROM
6. foo
7. )
8. SELECT
9. circumference,
10. color
11. FROM
12. table_1 AS table_0
13. WHERE
14. circumference > 10
15. AND color <> 'red'

Operator precedence

This table shows operator precedence. Use parentheses () to prioritize operations and for function calls (see the discussion below.)

Group Operators Precedence Associativity
parentheses () 0 see below
identifier dot . 1
unary - + ! == 2
range .. 3
mul * / % 4 left-to-right
add + - 5 left-to-right
compare == != <= >= < > 6 left-to-right
coalesce ?? 7 left-to-right
and && 8 left-to-right
or || 9 left-to-right
function call 10

Parentheses

PRQL uses parentheses () for several purposes:

  • Parentheses group operands to control the order of evaluation, for example: ((1 + x) * y)
  • Parentheses delimit an inner transform for the group () and window () transforms.
  • Parentheses delimit a minus sign of a function argument, for example: add (-1) (-3)
  • Parentheses delimit nested function calls that contain a pipe, either the | symbol or a new line. “Nested” means within a transform; i.e. not just the main pipeline, for example: (column-name | in 0..20)
  • Parentheses wrap a function call that is part of a larger expression on the right-hand side of an assignment, for example: round 0 (sum distance)
  • Parentheses are not required for expressions that do not contain function calls, for example: foo + bar.

Here’s a set of examples of these rules:

PRQL

1. from employees
2. # Requires parentheses, because it contains a pipe
3. derive is_proximate = (distance | in 0..20)
4. # Requires parentheses, because it's a function call
5. derive total_distance = (sum distance)
6. # `??` doesn't require parentheses, as it's not a function call
7. derive min_capped_distance = (min distance ?? 5)
8. # No parentheses needed, because no function call
9. derive travel_time = distance / 40
10. # No inner parentheses needed around `1+1` because no function call
11. derive distance_rounded_2_dp = (round 1+1 distance)
12. derive [
13. # Requires parentheses, because it contains a pipe
14. is_far = (distance | in 100..),
15. # The left value of the range requires parentheses,
16. # because of the minus sign
17. is_negative = (distance | in (-100..0)),
18. # ...this is equivalent
19. is_negative = (distance | in (-100)..0),
20. # Doesn't require parentheses, because it's in a list (confusing, see footnote)!
21. average_distance = average distance,
22. ]
23. # Requires parentheses because of the minus sign
24. sort (-distance)
25. # A list is fine too
26. sort [-distance]

SQL

1. SELECT
2. *,
3. distance BETWEEN 0 AND 20 AS is_proximate,
4. SUM(distance) OVER () AS total_distance,
5. MIN(COALESCE(distance, 5)) OVER () AS min_capped_distance,
6. distance / 40 AS travel_time,
7. ROUND(distance, 2) AS distance_rounded_2_dp,
8. distance >= 100 AS is_far,
9. distance BETWEEN -100 AND 0,
10. distance BETWEEN -100 AND 0 AS is_negative,
11. AVG(distance) OVER () AS average_distance
12. FROM
13. employees
14. ORDER BY
15. distance DESC

Note: The total_distance statement below generates an error because the function is not in a list. (The PRQL compiler should display a better error message.)

PRQL

1. from employees
2. derive total_distance = sum distance # generates the error shown below
3. derive other_distance = (sum distance) # works as expected

Error

1. Error:
2. ╭─[:2:29]
3. │
4. 2 │ derive total_distance = sum distance # generates the error shown below
5. │                             ────┬───
6. │                                 ╰───── Unknown name distance
7. ───╯

Note

We’re continuing to think whether these rules can be more intuitive. We’re also planning to make the error messages much better, so the compiler can help out.