Skip to content

Latest commit

 

History

History
65 lines (51 loc) · 2.13 KB

select-insert.md

File metadata and controls

65 lines (51 loc) · 2.13 KB

SELECT ⇒ INSERT

The following scenario is very common in adding new records:

  • try finding a specific record, and if found - return its id;
  • if no record found, add a new one and return the new id.
-- a simple table example
CREATE TABLE Users(
	id SERIAL PRIMARY KEY,
	name TEXT UNIQUE -- unique user name
);

Let's implement a function, according to that logic, to search by user's name, and return a new or existing id of the record.

function getInsertUserId(name) {
    return db.task('getInsertUserId', t => {
            return t.oneOrNone('SELECT id FROM Users WHERE name = $1', name, u => u && u.id)
                .then(userId => {
                    return userId || t.one('INSERT INTO Users(name) VALUES($1) RETURNING id', name, u => u.id);
                });
        });
}

Example of calling the function:

getInsertUserId('name')
    .then(userId => {
        // use the id;
    })
    .catch(error => {
        // something went wrong;
    });

The same function getInsertUserId, using ES7 async syntax:

async function getInsertUserId(name) {
    return db.task('getInsertUserId', async t => {
        const userId = await t.oneOrNone('SELECT id FROM Users WHERE name = $1', name, u => u && u.id);
        return userId || await t.one('INSERT INTO Users(name) VALUES($1) RETURNING id', name, u => u.id);
    });
}

Single-query alternative

It is possible to wrap the whole operation into a single query, which would offer a better performance, executing always just one query, and more importantly - proper data integrity, by making sure that a parallel request would not try to execute a second INSERT.

Implementing such a query however isn't trivial, and it can vary based on whether it is for PostgreSQL 9.5+ or an older version of the server.

The following posts will help you get started writing your own single-query solution for this: