diff --git a/CHANGELOG.md b/CHANGELOG.md index 90384c2..6c3715f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ Only accretive/fixative changes will be made from now on. +* 1.3.next in progress + * Address [#268](https://github.com/seancorfield/next-jdbc/issues/268) by expanding the documentation around `insert-multi!` and `insert!`. + * 1.3.909 -- 2023-12-16 * Address [#267](https://github.com/seancorfield/next-jdbc/issues/267) by adding the `:schema-opts` option to override the default conventions for identifying foreign keys in columns. * Address [#264](https://github.com/seancorfield/next-jdbc/issues/264) by letting `insert-multi!` accept empty rows (and producing an empty result vector). This improves compatibility with `clojure.java.jdbc`. diff --git a/doc/friendly-sql-functions.md b/doc/friendly-sql-functions.md index 0265045..22e412d 100644 --- a/doc/friendly-sql-functions.md +++ b/doc/friendly-sql-functions.md @@ -42,9 +42,14 @@ Given a table name (as a keyword) and a hash map of column names and values, thi {:suffix "RETURNING *"}) ``` +If you have multiple rows (hash maps) to insert and they all have the same +set of keys, you can use `insert-multi!` instead (see below), which will +perform a single multi-row insertion, which will generally be faster. + ## `insert-multi!` -Given a table name (as a keyword), a vector of column names, and a vector of row value vectors, this performs a multi-row insertion into the database: +Given a table name (as a keyword), a vector of column names, and a vector of +row value vectors, this performs a single multi-row insertion into the database: ```clojure (sql/insert-multi! ds :address @@ -59,7 +64,11 @@ Given a table name (as a keyword), a vector of column names, and a vector of row "Aunt Sally" "sour@lagunitas.beer"] {:return-keys true}) ``` -Given a table name (as a keyword) and a vector of hash maps, this performs a multi-row insertion into the database: +All the row vectors must be the same length, and must match the number of +columns specified. + +Given a table name (as a keyword) and a vector of hash maps, this performs a +single multi-row insertion into the database: ```clojure (sql/insert-multi! ds :address @@ -73,7 +82,15 @@ Given a table name (as a keyword) and a vector of hash maps, this performs a mul "Aunt Sally" "sour@lagunitas.beer"] {:return-keys true}) ``` -> Note: this expands to a single SQL statement with placeholders for every +All the hash maps must have the same set of keys, so that the vector of hash +maps can be converted to a vector of columns names and a vector of row value +vectors, as above, so a single multi-row insertion can be performed. + +If you wish to insert multiple hash maps that do not have identical keys, you +need to iterate over `insert!` and insert one row at a time, which will +generally be much slower. + +> Note: both of these expand to a single SQL statement with placeholders for every value being inserted -- for large sets of rows, this may exceed the limits on SQL string size and/or number of parameters for your JDBC driver or your database. Several databases have a limit of 1,000 parameter placeholders. diff --git a/doc/migration-from-clojure-java-jdbc.md b/doc/migration-from-clojure-java-jdbc.md index 02dba10..24b9858 100644 --- a/doc/migration-from-clojure-java-jdbc.md +++ b/doc/migration-from-clojure-java-jdbc.md @@ -64,7 +64,7 @@ If you were using other forms of the `db-spec` hash map, you'll need to adjust t The `next.jdbc.sql` namespace contains several functions with similarities to `clojure.java.jdbc`'s core API: * `insert!` -- similar to `clojure.java.jdbc/insert!` but only supports inserting a single map, -* `insert-multi!` -- similar to `clojure.java.jdbc/insert-multi!` but only supports inserting columns and a vector of row values, +* `insert-multi!` -- similar to `clojure.java.jdbc/insert-multi!` but only supports inserting columns and a vector of row values, or a sequence of hash maps _that all have the same keys_ -- unlike `clojure.java.jdbc/insert-multi!`, you should always get a single multi-row insertion, * `query` -- similar to `clojure.java.jdbc/query`, * `find-by-keys` -- similar to `clojure.java.jdbc/find-by-keys` but will also accept a partial where clause (vector) instead of a hash map of column name/value pairs, * `get-by-id` -- similar to `clojure.java.jdbc/get-by-id`, diff --git a/src/next/jdbc/sql.clj b/src/next/jdbc/sql.clj index 940ca4b..4400b8b 100644 --- a/src/next/jdbc/sql.clj +++ b/src/next/jdbc/sql.clj @@ -52,8 +52,8 @@ generated keys. Given a connectable object, a table name, a sequence of hash maps of data, - inserts the data as multiple rows in the database and attempts to return - a vector of maps of generated keys. + which all have the same set of keys, inserts the data as multiple rows in + the database and attempts to return a vector of maps of generated keys. If called with `:batch` true will call `execute-batch!` - see its documentation for situations in which the generated keys may or may not be returned as well as