< Prev: SELECT
Up: Query Building
Next: UPDATE >

Query Building: INSERT

Contents

Basic example

  contents
SQL
INSERT INTO public.users (name, email)
VALUES ('bob', 'bob@email.com'), ('alice', 'alice@email.com');
Go
u := tables.USERS()

// ...if you use ToSQL
query, args := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    ToSQL()
_, err := DB.Exec(query, args...)
if err != nil {
    /* handle error */
}

// ...if you use Exec
_, err := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    Exec(DB, 0)
if err != nil {
    /* handle error */
}

Getting the last inserted AUTO_INCREMENT/SERIAL ID

  contents
SQL
--------------
-- Postgres --
--------------

INSERT INTO public.users (name, email)
VALUES ('bob', 'bob@email.com'), ('alice', 'alice@email.com')
RETURNING u.user_id;

-----------
-- MySQL --
-----------

INSERT INTO public.users (name, email)
VALUES ('bob', 'bob@email.com'), ('alice', 'alice@email.com');
SELECT last_insert_id();
Go
u := tables.USERS()
var lastInsertID int64
var lastInsertIDs []int64

//----------//
// Postgres //
//----------//
// Note: Postgres is able to return multiple INSERT-ed IDs, not just
// the last inserted one

// ...if you use ToSQL
query, args := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    Returning(u.USER_ID).
    ToSQL()
rows, err := DB.Query(query, args...)
if err != nil {
    /* handle error */
}
for rows.Next() {
    err = rows.Scan(&lastInsertID)
    if err != nil {
        /* handle error */
    }
    lastInsertIDs = append(lastInsertIDs, lastInsertID)
}

// ...if you use Returningx (see [Struct Mapping](/sq/basics/struct-mapping.html#select-one-vs-many))
err := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    Returningx(func(row *sq.Row) {
        lastInsertID = row.Int64(u.USER_ID)
    }, func() {
        lastInsertIDs = append(lastInsertIDs, lastInsertID)
    }).
    Fetch(DB)
if err != nil {
    /* handle error */
}

// ...if you use ReturningRowx (see [Struct Mapping](/sq/basics/struct-mapping.html#select-one-vs-many))
// ReturningRowx only returns one row, which means in this case it will only
// return the user_id of 'bob'.
err := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    ReturningRowx(func(row *sq.Row) {
        lastInsertID = row.Int64(u.USER_ID)
    }).
    Fetch(DB)
if err != nil {
    /* handle error */
}

//-------//
// MySQL //
//-------//

// ...if you use ToSQL
query, args := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    Returning(u.USER_ID).
    ToSQL()
res, err := DB.Exec(query, args...)
if err != nil {
    /* handle error */
}
lastInsertID, err := res.LastInsertId() // user_id for 'bob'
if err != nil {
    /* handle error */
}

// ...if you use Exec
lastInsertID, _, err := sq.InsertInto(u) // user_id for 'bob'
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    Exec(DB, sq.ElastInsertID)
if err != nil {
    /* handle error */
}

INSERT and ignore duplicates

  contents
SQL
--------------
-- Postgres --
--------------

INSERT INTO public.users (name, email)
VALUES ('bob', 'bob@email.com'), ('alice', 'alice@email.com')
ON CONFLICT DO NOTHING;

-----------
-- MySQL --
-----------

-- Ignoring all errors ([including wrong datatype and foreign key errors](https://stackoverflow.com/a/4596409))
-- Only use if you really don't care about any possible errors
INSERT IGNORE INTO public.users (name, email)
VALUES ('bob', 'bob@email.com'), ('alice', 'alice@email.com');

-- Ignoring duplicates by assigning a column to itself
-- (MySQL will not run UPDATE if the value is the same)
INSERT INTO public.users (name, email)
VALUES ('bob', 'bob@email.com'), ('alice', 'alice@email.com')
ON DUPLICATE KEY DO UPDATE email = email;
Go
u := tables.USERS()

//----------//
// Postgres //
//----------//

// ...if you use ToSQL
query, args := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    OnConflict().DoNothing().
    ToSQL()
_, err := DB.Exec(query, args...)
if err != nil {
    /* handle error */
}

// ...if you use Exec
_, err := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    OnConflict().DoNothing().
    Exec(DB, 0)
if err != nil {
    /* handle error */
}

//-------//
// MySQL //
//-------//

// Ignoring all errors

// ...if you use ToSQL
query, args := sq.InsertIgnoreInto(u)
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    ToSQL()
_, err := DB.Exec(query, args...)
if err != nil {
    /* handle error */
}

// ...if you use Exec
_, _, err := sq.InsertIgnoreInto(u)
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    Exec(DB, 0)
if err != nil {
    /* handle error */
}

// Ignoring duplicates by assigning a column to itself

// ...if you use ToSQL
query, args := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    OnDuplicateKeyUpdate(u.EMAIL.Set(u.EMAIL)).
    ToSQL()
_, err := DB.Exec(query, args...)
if err != nil {
    /* handle error */
}

// ...if you use Exec
_, _, err := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    OnDuplicateKeyUpdate(u.EMAIL.Set(u.EMAIL)).
    Exec(DB, 0)
if err != nil {
    /* handle error */
}

Upsert

  contents
SQL
--------------
-- Postgres --
--------------
-- [postgrestutorial.com: upsert](https://www.postgresqltutorial.com/postgresql-upsert/)

-- Using conflict column(s)
INSERT INTO public.users (name, email)
VALUES ('bob', 'bob@email.com'), ('alice', 'alice@email.com')
ON CONFLICT (email) DO UPDATE SET
name = EXCLUDED.name;

-- Using conflict constraint
INSERT INTO public.users (name, email)
VALUES ('bob', 'bob@email.com'), ('alice', 'alice@email.com')
ON CONFLICT ON CONSTRAINT users_email_key DO UPDATE SET
name = EXCLUDED.name;

-----------
-- MySQL --
-----------
-- [mysqltutorial.org: upsert](https://www.mysqltutorial.org/mysql-insert-or-update-on-duplicate-key-update/)

INSERT INTO public.users (name, email)
VALUES ('bob', 'bob@email.com'), ('alice', 'alice@email.com')
ON DUPLICATE KEY DO UPDATE
name = VALUES(name);
Go
u := tables.USERS()

//----------//
// Postgres //
//----------//

// Using conflict columns(s)

// ...if you use ToSQL
query, args := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    OnConflict(u.EMAIL).
    DoUpdateSet(
        u.NAME.Set(sq.Excluded(u.NAME)),
    ).
    ToSQL()
_, err := DB.Exec(query, args...)
if err != nil {
    /* handle error */
}

// ...if you use Exec
_, err := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    OnConflict(u.EMAIL).
    DoUpdateSet(
        u.NAME.Set(sq.Excluded(u.NAME)),
    ).
    Exec(DB, 0)
if err != nil {
    /* handle error */
}

// Using conflict constraint

// ...if you use ToSQL
query, args := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    OnConflictOnConstraint("users_email_key").
    DoUpdateSet(
        u.NAME.Set(sq.Excluded(u.NAME)),
    ).
    ToSQL()
_, err := DB.Exec(query, args...)
if err != nil {
    /* handle error */
}

// ...if you use Exec
_, err := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    OnConflictOnConstraint("users_email_key").
    DoUpdateSet(
        u.NAME.Set(sq.Excluded(u.NAME)),
    ).
    Exec(DB, 0)
if err != nil {
    /* handle error */
}

//-------//
// MySQL //
//-------//

// ...if you use ToSQL
query, args := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    OnDuplicateKeyUpdate(
        u.NAME.Set(sq.Values(u.NAME)),
    ).
    ToSQL()
_, err := DB.Exec(query, args...)
if err != nil {
    /* handle error */
}

// ...if you use Exec
_, _, err := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Values("bob", "bob@email.com").
    Values("alice", "alice@email.com").
    OnDuplicateKeyUpdate(
        u.NAME.Set(sq.Values(u.NAME)),
    ).
    Exec(DB, 0)
if err != nil {
    /* handle error */
}

INSERT from SELECT

  contents
SQL
INSERT INTO public.users (name, email)
SELECT name, email
FROM public.users
WHERE users.name = 'bob';
Go
u := tables.USERS()

// ...if you use ToSQL
query, args := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Select(sq.
        Select(u.NAME, u.EMAIL).
        From(u).
        Where(u.NAME.EqString("bob")),
    ).
    ToSQL()
_, err := DB.Exec(query, args...)
if err != nil {
    /* handle error */
}

// ...if you use Exec
_, err := sq.InsertInto(u).
    Columns(u.NAME, u.EMAIL).
    Select(sq.
        Select(u.NAME, u.EMAIL).
        From(u).
        Where(u.NAME.EqString("bob")),
    ).
    Exec(DB, 0)
if err != nil {
    /* handle error */
}

Binding values to columns

  contents

Alternatively, you can bind values to columns in an insert statement. This helps if you are inserting a lot of columns and you don't want to accidentally mess up the order or miss a value.

Inserting one entry
-- SQL
INSERT INTO public.users (name, email)
VALUES ('bob', 'bob@email.com');
// Go
u := tables.USERS()
user := User{Name: "bob", Email: "bob@email.com"}

// ...if you use ToSQL
query, args := sq.InsertInto(u).
    Valuesx(func(col *sq.Column) {
        col.SetString(u.NAME, user.Name)
        col.SetString(u.EMAIL, user.Email)
    }).
    ToSQL()
_, err := DB.Exec(query, args...)
if err != nil {
    /* handle error */
}

// ...if you use Exec
_, err := sq.InsertInto(u).
    Valuesx(func(col *sq.Column) {
        col.SetString(u.NAME, user.Name)
        col.SetString(u.EMAIL, user.Email)
    }).
    Exec(DB, 0)
if err != nil {
    /* handle error */
}
Inserting many entries
-- SQL
INSERT INTO public.users (name, email)
VALUES
    ('bob', 'bob@email.com'),
    ('alice', 'alice@email.com'),
    ('eve', 'eve@email.com');
// Go
u := tables.USERS()
users := []User{
    {Name: "bob",   Email: "bob@email.com"},
    {Name: "alice", Email: "alice@email.com"},
    {Name: "eve",   Email: "eve@email.com"},
}

// ...if you use ToSQL
query, args := sq.InsertInto(u).
    Valuesx(func(col *sq.Column) {
        for _, user := range users {
            col.SetString(u.NAME, user.Name)
            col.SetString(u.EMAIL, user.Email)
        }
    }).
    ToSQL()
_, err := DB.Exec(query, args...)
if err != nil {
    /* handle error */
}

// ...if you use Exec
_, err := sq.InsertInto(u).
    Valuesx(func(col *sq.Column) {
        for _, user := range users {
            col.SetString(u.NAME, user.Name)
            col.SetString(u.EMAIL, user.Email)
        }
    }).
    Exec(DB, 0)
if err != nil {
    /* handle error */
}

Clause manipulation

  contents
Clauses are just struct fields, you can either use method chaining to add clauses or manipulate the struct fields directly.
Clauses: WITH (postgres only), INSERT INTO, INSERT IGNORE INTO (mysql only), VALUES, SELECT, ON CONFLICT (postgres only), ON DUPLICATE KEY UPDATE (mysql only), RETURNING (postgres only)
< Prev: SELECT
Up: Query Building
Next: UPDATE >