Standard library

The standard library currently contains commonly used functions that are used in SQL. It’s not yet as broad as we’d like, and we’re very open to expanding it.

Currently s-strings are an escape-hatch for any function that isn’t in our standard library. If we find ourselves using them for something frequently, raise an issue and we’ll add it to the stdlib.

Here’s the source of the current PRQL std:

Note

PRQL 0.9.0 has started supporting different DB implementations for standard library functions. The source is the std.sql.

  1. # The PRQL standard library defines the following functions and transforms.
  2. # The definitions are whitespace insensitive, and have this form:
  3. #
  4. # '''
  5. # let my_func = param1 param2 ... -> <return_type> body_expr
  6. # '''
  7. #
  8. # Where:
  9. # * `my_func` is the name of the function
  10. # * `param1` is the first parameter optionally followed by a type in "< ... >"
  11. # * `param2` etc. follow the same pattern as param1
  12. # * `<return_type>` is the type of result wrapped in "< ... >"
  13. # * `body_expr` defines the function body that creates the result.
  14. # It can be PRQL code or `internal ...` to indicate internal compiler code.
  15. # Operators
  16. let mul = left right -> <int || float> internal std.mul
  17. let div_i = left right -> <int || float> internal std.div_i
  18. let div_f = left right -> <int || float> internal std.div_f
  19. let mod = left right -> <int || float> internal std.mod
  20. let add = left<int || float || timestamp || date> right<int || float || timestamp || date> -> <int || float || timestamp || date> internal std.add
  21. let sub = left<int || float || timestamp || date> right<int || float || timestamp || date> -> <int || float || timestamp || date> internal std.sub
  22. let eq = left right -> <bool> internal std.eq
  23. let ne = left right -> <bool> internal std.ne
  24. let gt = left right -> <bool> internal std.gt
  25. let lt = left right -> <bool> internal std.lt
  26. let gte = left right -> <bool> internal std.gte
  27. let lte = left right -> <bool> internal std.lte
  28. let and = left<bool> right<bool> -> <bool> internal std.and
  29. let or = left<bool> right<bool> -> <bool> internal std.or
  30. let coalesce = left right -> internal std.coalesce
  31. let regex_search = text pattern -> <bool> internal std.regex_search
  32. let neg = expr<int || float> -> <int || float> internal std.neg
  33. let not = expr<bool> -> <bool> internal std.not
  34. # Types
  35. ## Type primitives
  36. type int
  37. type float
  38. type bool
  39. type text
  40. type date
  41. type time
  42. type timestamp
  43. type `func`
  44. type anytype
  45. ## Generic array
  46. # TODO: an array of anything, not just nulls
  47. type array = [anytype]
  48. ## Scalar
  49. type scalar = int || float || bool || text || date || time || timestamp || null
  50. type tuple = {anytype..}
  51. ## Range
  52. type range = {start = scalar, end = scalar}
  53. ## Relation (an array of tuples)
  54. type relation = [tuple]
  55. ## Transform
  56. type transform = (func relation -> relation)
  57. # Functions
  58. ## Relational transforms
  59. let from = func
  60. `default_db.source` <relation>
  61. -> <relation> internal from
  62. let select = func
  63. columns <scalar || tuple>
  64. tbl <relation>
  65. -> <relation> internal select
  66. let filter = func
  67. condition <bool>
  68. tbl <relation>
  69. -> <relation> internal filter
  70. let derive = func
  71. columns <scalar || tuple>
  72. tbl <relation>
  73. -> <relation> internal derive
  74. let aggregate = func
  75. columns <scalar || tuple>
  76. tbl <relation>
  77. -> <relation> internal aggregate
  78. let sort = func
  79. by <scalar || tuple>
  80. tbl <relation>
  81. -> <relation> internal sort
  82. let take = func
  83. expr <anytype>
  84. tbl <relation>
  85. -> <relation> internal take
  86. let join = func
  87. `default_db.with` <relation>
  88. condition <bool>
  89. `noresolve.side`:inner
  90. tbl <relation>
  91. -> <relation> internal join
  92. let group = func
  93. by<scalar || tuple>
  94. pipeline <transform>
  95. tbl <relation>
  96. -> <relation> internal group
  97. let window = func
  98. rows:0..0
  99. range:0..0
  100. expanding <bool>:false
  101. rolling <int>:0
  102. pipeline <transform>
  103. tbl <relation>
  104. -> <relation> internal window
  105. let append = `default_db.bottom`<relation> top<relation> -> <relation> internal append
  106. let intersect = `default_db.bottom`<relation> top<relation> -> <relation> (
  107. t = top
  108. join (b = bottom) (tuple_every (tuple_map _eq (tuple_zip t.* b.*)))
  109. select t.*
  110. )
  111. let remove = `default_db.bottom`<relation> top<relation> -> <relation> (
  112. t = top
  113. join side:left (b = bottom) (tuple_every (tuple_map _eq (tuple_zip t.* b.*)))
  114. filter (tuple_every (tuple_map _is_null b.*))
  115. select t.*
  116. )
  117. let loop = func
  118. pipeline <transform>
  119. top <relation>
  120. -> <relation> internal loop
  121. ## Aggregate functions
  122. # These return either a scalar when used within `aggregate`, or a column when used anywhere else.
  123. let min = column <array> -> <int || float || null> internal std.min
  124. let max = column <array> -> <int || float || null> internal std.max
  125. let sum = column <array> -> <int || float> internal std.sum
  126. let average = column <array> -> <float || null> internal std.average
  127. let stddev = column <array> -> <float || null> internal std.stddev
  128. let all = column <array> -> <bool> internal std.all
  129. let any = column <array> -> <bool> internal std.any
  130. let concat_array = column <array> -> <text> internal std.concat_array
  131. # Counts number of items in the column.
  132. # Note that the count will include null values.
  133. let count = column<array> -> <int> internal std.count
  134. # Deprecated in favour of filterning input to the [std.count] function (not yet implemented).
  135. @{deprecated}
  136. let count_distinct = column <array> -> internal std.count_distinct
  137. ## Window functions
  138. let lag = offset <int> column <array> -> internal std.lag
  139. let lead = offset <int> column <array> -> internal std.lead
  140. let first = column <array> -> internal std.first
  141. let last = column <array> -> internal std.last
  142. let rank = column <array> -> internal std.rank
  143. let rank_dense = column <array> -> internal std.rank_dense
  144. let row_number = column <array> -> internal std.row_number
  145. ## Misc functions
  146. let round = n_digits column -> <scalar> internal std.round
  147. let as = `noresolve.type` column -> <scalar> internal std.as
  148. let in = pattern value -> <bool> internal in
  149. ## Tuple functions
  150. let tuple_every = func list -> <bool> internal tuple_every
  151. let tuple_map = func fn <func> list -> internal tuple_map
  152. let tuple_zip = func a b -> internal tuple_zip
  153. let _eq = func a -> internal _eq
  154. let _is_null = func a -> _param.a == null
  155. ## Misc
  156. let from_text = input<text> `noresolve.format`:csv -> <relation> internal from_text
  157. ## String functions
  158. let lower = column -> <text> internal std.lower
  159. let upper = column -> <text> internal std.upper
  160. ## File-reading functions, primarily for DuckDB
  161. let read_parquet = source<text> -> <relation> internal std.read_parquet
  162. let read_csv = source<text> -> <relation> internal std.read_csv
  163. ## PRQL compiler functions
  164. let prql_version = -> <text> internal prql_version

And a couple of examples:

PRQL

  1. from employees
  2. derive {
  3. gross_salary = (salary + payroll_tax | as int),
  4. gross_salary_rounded = (gross_salary | round 0),
  5. time = s"NOW()", # an s-string, given no `now` function exists in PRQL
  6. }

SQL

  1. SELECT
  2. *,
  3. CAST(salary + payroll_tax AS int) AS gross_salary,
  4. ROUND(CAST(salary + payroll_tax AS int), 0) AS gross_salary_rounded,
  5. NOW() AS time
  6. FROM
  7. employees

Example of different implementations of division and integer division:

PRQL

  1. prql target:sql.sqlite
  2. from [{x = 13, y = 5}]
  3. select {
  4. quotient = x / y,
  5. int_quotient = x // y,
  6. }

SQL

  1. WITH table_0 AS (
  2. SELECT
  3. 13 AS x,
  4. 5 AS y
  5. )
  6. SELECT
  7. (x * 1.0 / y) AS quotient,
  8. ROUND(ABS(x / y) - 0.5) * SIGN(x) * SIGN(y) AS int_quotient
  9. FROM
  10. table_0

PRQL

  1. prql target:sql.mysql
  2. from [{x = 13, y = 5}]
  3. select {
  4. quotient = x / y,
  5. int_quotient = x // y,
  6. }

SQL

  1. WITH table_0 AS (
  2. SELECT
  3. 13 AS x,
  4. 5 AS y
  5. )
  6. SELECT
  7. (x / y) AS quotient,
  8. (x DIV y) AS int_quotient
  9. FROM
  10. table_0