Query syntax reference#
This page defines everything that can appear in a predicate — the where=
argument of Table.select,
Table.read, and
Table.count. The syntax intentionally parallels
pyarrow’s, in both its expression form and its tuple form, so predicates
written for one usually read verbatim in the other.
Expressions#
field() names a column and supports the comparison operators
directly; each comparison yields an Expression:
Predicate |
Meaning |
|---|---|
|
equal to |
|
not equal to |
|
ordered comparison |
|
equal to any element of |
|
the row’s value is missing |
|
the row’s value is present |
Expressions combine with the logical operators:
Combinator |
Meaning |
|---|---|
|
both |
|
either |
|
negation |
Python gives &, |, and ~ higher precedence than comparisons, so each
comparison must be parenthesized — this is a property of the language, and
pyarrow users will already have the habit:
(field("kind") == "automatic") & (field("t_air") > 22.0) # correct
field("kind") == "automatic" & field("t_air") > 22.0 # wrong: & binds first
A bare field("x") is not a predicate; passing one raises
SchemaError.
Values#
A comparison value should live in the column’s value domain:
Numeric columns compare against Python or NumPy numbers. Mixed integer/float comparisons are exact — the engine compares in Python’s object domain, so a
uint64beyond 2⁵³ is never silently rounded throughfloat64.Fixed-length string columns compare against
str(or UTF-8bytes); ordering is bytewise, which for ASCII and UTF-8 equals codepoint order.Boolean columns compare against
True/False.Categorical columns compare against labels, never codes —
field("payment_type") == "Cash". An unknown label under==orisinsimply matches nothing; an unknown label under an ordering operator raisesSchemaError, since it has no defined position. Ordering comparisons on a categorical follow the declared category order (the code order), which is chiefly meaningful for columns declared withordered=True.Datetime columns, stored as integers by an application-level codec (H5Col defines no datetime type), compare against the encoded integers — encode the query bound with the same codec used to write the column, as the taxi example demonstrates.
Tuple form#
Anywhere an expression is accepted, pyarrow’s tuple filters work as well:
Form |
Meaning |
|---|---|
|
one predicate |
|
AND of the tuples |
|
OR of AND-groups (disjunctive normal form) |
The operator token is a string: "=" or "==", "!=", "<", "<=",
">", ">=", "in", or "not in" ("in" takes a sequence of values).
The two spellings below are the same query:
table.select((field("kind") == "automatic") & (field("t_air") > 22.0))
table.select([("kind", "==", "automatic"), ("t_air", ">", 22.0)])
An empty list selects every row. (pyarrow, by contrast, rejects an empty
filters list as malformed — this is one small place the two APIs differ.)
Missing values: three-valued logic#
Comparisons involving a missing value are neither true nor false — they are unknown, and a row is selected only when its whole predicate evaluates to true. The connectives follow Kleene logic, the same rules SQL and pyarrow apply:
|
|
|
|
|
|---|---|---|---|---|
true |
unknown |
unknown |
true |
false |
false |
unknown |
false |
unknown |
true |
unknown |
unknown |
unknown |
unknown |
unknown |
The practical consequences:
field("x") == 5never matches a missing row — and neither does~(field("x") == 5)orfield("x") != 5. Negation does not turn unknown into true.The only predicates that see missing rows are
is_null()andis_valid(). They are always definite (a row is either present or not), and they negate into each other:~field("x").is_null()is exactlyfield("x").is_valid().To include missing rows in an otherwise value-based selection, say so:
(field("x") > 5) | field("x").is_null().
Boolean columns cannot hold missing values, so their comparisons are always definite.
Errors and limits#
A structurally malformed
where=value — an unknown operator token, a shape that is neither an expression nor tuples — raisesSchemaErrorimmediately, fromselect(),read(), orcount()itself.A predicate naming a column the table does not have raises
KeyErrorwhen the selection is first evaluated; predicates on list columns are not supported and raiseSchemaErrorat the same point.Distributing AND over OR during normalization caps at 1,024 AND-terms; a predicate that expands beyond that (deeply nested negated conjunctions can) is rejected with
SchemaErrorand should be simplified. A filter already written as a list of OR-groups is not subject to the cap.
Correspondence with pyarrow#
pyarrow |
h5col |
|---|---|
|
|
|
|
|
|
|
|
|
the same tuples, passed to |
null semantics in filters (Kleene) |
the same three-valued semantics |
The differences are the import — field comes from h5col — and the value
domains noted above (labels for categoricals, encoded integers for
datetimes).