Document more clauses

This commit is contained in:
Sean Corfield 2021-02-07 03:40:29 -08:00
parent c00fbffe30
commit bb16567d50
2 changed files with 151 additions and 3 deletions

View file

@ -61,25 +61,173 @@ user=> (sql/format {:with [[:stuff {:columns [:id :name]}]
> Note: HoneySQL 0.6.2 introduced support for CTEs a long time ago and it expected the pair (of result set and query) to be wrapped in a sequence, even though you can only have a single CTE. For backward compatibility, HoneySQL 2.0 accepts that format but it should be considered deprecated. > Note: HoneySQL 0.6.2 introduced support for CTEs a long time ago and it expected the pair (of result set and query) to be wrapped in a sequence, even though you can only have a single CTE. For backward compatibility, HoneySQL 2.0 accepts that format but it should be considered deprecated.
## intersect, union, union-all, except, except-all ## intersect, union, union-all, except, except-all
These all expect a sequence of SQL clauses, those clauses
will be wrapped in parentheses, and the SQL keyword interspersed
between those clauses.
```clojure
user=> (sql/format '{union [{select (id,status) from (table-a)}
{select (id,(event status) from (table-b))}]})
["(SELECT id, status FROM table_a) UNION (SELECT id, event AS status, from, table_b)"]
```
## select, select-distinct ## select, select-distinct
`:select` expects a sequence of SQL entities (column names
or expressions). Any of the SQL entities can be a pair of entity and alias. If you are selecting an expression, you would most
often provide an alias for the expression, but it can be omitted
as in the following:
```clojure
user=> (sql/format '{select (id, ((* cost 2)), (event status))
from (table)})
["SELECT id, cost * ?, event AS status FROM table" 2]
```
With an alias on the expression:
```clojure
user=> (sql/format {:select [:id, [[:* :cost 2] :total], [:event :status]]
:from [:table]})
["SELECT id, cost * ? AS total, event AS status FROM table" 2]
```
`:select-distinct` works the same way but produces `SELECT DISTINCT`.
## insert-into ## insert-into
There are two use cases with `:insert-into`. The first case
takes just a simple SQL entity (the table name). The more
complex case takes a pair of a SQL entity and a SQL query.
In that second case, you can specify the columns by using
a pair of the table name and a sequence of column names.
For the first case, you'll use the `:values` clause and you
may use the `:columns` clause as well.
```clojure
user=> (sql/format {:insert-into :transport
:values [[1 "Car"] [2 "Boat"] [3 "Bike"]]})
["INSERT INTO transport VALUES (?, ?), (?, ?), (?, ?)" 1 "Car" 2 "Boat" 3 "Bike"]
user=> (sql/format {:insert-into :transport
:columns [:id :name]
:values [[1 "Car"] [2 "Boat"] [3 "Bike"]]})
["INSERT INTO transport (id, name) VALUES (?, ?), (?, ?), (?, ?)" 1 "Car" 2 "Boat" 3 "Bike"]
```
The second case:
```clojure
user=> (sql/format '{insert-into (transport {select (id, name) from (cars)})})
["INSERT INTO transport SELECT id, name FROM cars"]
user=> (sql/format '{insert-into ((transport (id, name)) {select (*) from (cars)})})
["INSERT INTO transport (id, name) SELECT * FROM cars"]
```
## update ## update
`:update` expects either a simple SQL entity (table name)
or a pair of the table name and an alias:
```clojure
user=> (sql/format {:update :transport
:set {:name "Yacht"}
:where [:= :id 2]})
["UPDATE transport SET name = ? WHERE id = ?" "Yacht" 2]
```
## delete, delete-from ## delete, delete-from
`:delete-from` is the simple use case here, accepting just a
SQL entity (table name). `:delete` allows for deleting from
multiple tables, accepting a sequence of either table names
or aliases:
```clojure
user=> (sql/format '{delete-from transport where (= id 1)})
["DELETE FROM transport WHERE id = ?" 1]
user=> (sql/format {:delete [:order :item]
:from [:order]
:join [:item [:= :order.item-id :item.id]]
:where [:= :item.id 42]})
["DELETE order, item FROM order INNER JOIN item ON order.item_id = item.id WHERE item.id = ?" 42]
```
## truncate ## truncate
`:truncate` accepts a simple SQL entity (table name):
```clojure
user=> (sql/format '{truncate transport})
["TRUNCATE transport"]
```
## columns ## columns
Wherever you need just a list of column names `:columns`
accepts a sequence of SQL entities (names). We saw an
example above with `:insert-into`.
## set (ANSI) ## set (ANSI)
`:set` accepts a hash map of SQL entities and the values
that they should be assigned. This precedence -- between
`:columns` and `:from` -- corresponds to ANSI SQL which
is correct for most databases. The MySQL dialect that
HoneySQL 2.0 supports has a different precedence (below).
```clojure
user=> (sql/format {:update :order
:set {:line-count [:+ :line-count 1]}
:where [:= :item-id 42]})
["UPDATE order SET line_count = line_count + ? WHERE item_id = ?" 1 42]
```
## from ## from
`:from` accepts a single sequence argument that lists
one or more SQL entities. Each entity can either be a
simple table name (keyword or symbol) or a pair of a
table name and an alias:
```clojure
user=> (sql/format {:select [:username :name]
:from [:user :status]
:where [:and [:= :user.statusid :status.id]
[:= :user.id 9]]})
["SELECT username, name FROM user, status WHERE (user.statusid = status.id) AND (user.id = ?)" 9]
user=> (sql/format {:select [:u.username :s.name]
:from [[:user :u] [:status :s]]
:where [:and [:= :u.statusid :s.id]
[:= :u.id 9]]})
["SELECT u.username, s.name FROM user AS u, status AS s WHERE (u.statusid = s.id) AND (u.id = ?)" 9]
```
## using ## using
## join, left-join, right-join, inner-join, outer-join, full-join ## join, left-join, right-join, inner-join, outer-join, full-join
## cross-join ## cross-join
## set (MySQL) ## set (MySQL)
## where ## where
## group-by ## group-by
## having ## having
## order-by ## order-by
## limit, offset (MySQL) ## limit, offset (MySQL)
## for ## for
## lock (MySQL) ## lock (MySQL)
## values ## values
## on-conflict, on-constraint, do-nothing, do-update-set ## on-conflict, on-constraint, do-nothing, do-update-set
## returning ## returning

View file

@ -44,8 +44,8 @@
(assoc {} k data))) (assoc {} k data)))
(defn nest [& args] (generic :nest args)) (defn nest [& args] (generic :nest args))
(defn with [& args] (generic :with args)) (defn with [& args] (generic-1 :with args))
(defn with-recursive [& args] (generic :with-recursive args)) (defn with-recursive [& args] (generic-1 :with-recursive args))
;; these five need to supply an empty hash map since they wrap ;; these five need to supply an empty hash map since they wrap
;; all of their arguments: ;; all of their arguments:
(defn intersect [& args] (generic :intersect (cons {} args))) (defn intersect [& args] (generic :intersect (cons {} args)))