xtdb / learn-xtdb-datalog-today

Learn xtdb Datalog syntax
MIT License
7 stars 4 forks source link

Subqueries section #7

Open refset opened 3 years ago

refset commented 3 years ago
Hi all,
I had a question about Q2 from the aggregates section https://nextjournal.com/try/learn-crux-datalog-today/learn-crux-datalog-today#aggregates.
Particularly about adapting the following solution
(q '{:find [(min date)]
     :where [[_ :person/born date]]})
This returns the birthdate of the oldest person in our dataset.
The question is, can the query be adapted to also return the name of this person.
My naive idea was to do something like
(q '{:find [name (min date)]
     :where [[_ :person/born date]
             [_ :person/name name]]})
however this doesn't work because it will return a set of items where each item is the name of a different person.
So how can we couple the name to refer to the data coming from the aggregator. Can we only achieve this with 2 queries? Maybe we can only achieve this by also providing some relational list in the arguments? (edited) 
Nextjournal
Learn Crux Datalog Today
Learn Crux Datalog Today is derived from the classic learndatalogtoday.org tutorial materials, but adapted to focus on the Crux API and unique Datalog semantics, and extended with additional topics and exercises. It is an interactive tutorial designed to teach you the Crux dialect of Datalog. Datalog is a declarative database query language with roots in logic programming. Datalog has similar expressive power to SQL.
2 replies

refset:crux:  4 hours ago
Hi, good question! I think you're right that 2 queries is the answer, but using subqueries you can still treat it as one query:
(q '{:find [name date]
     :where [[(q '{:find [(min date)]
                   :where [[_ :person/born date]]}) [[date]]]
             [p :person/born date]
             [p :person/name name]]})
(note, I've not attempted to actually run this yet...)
That query may still return multiple names though, since multiple persons can share the same birth date, so you might want to also do an :order-by [[name :asc]] and :limit 1 if you are looking for a single deterministic result
For a more complex example of subqueries see here https://github.com/juxt/crux/blob/6d602bb5b6caed199f10fd8c3711cb034d49248a/crux-test/src/crux/fixtures/tpch.clj#L285-L317 
I checked and your solution did work. Thanks!