Postgres equivalent of MySQL's SET?

时间:2016-10-15 17:15:43

标签: javascript mysql sql node.js postgresql

I am trying to migrate to Postgres from MySQL and have run into a little bit of a problem. I have a form where the user fills out about 40 fields, and these values are inserted into the database. With MySQL I'm used to doing it like this:

INSERT INTO table_name SET name="John Smith", email="jsmith@gmail.com", website="jsmith.org";

I'm also using the mysql module with nodejs, and this is what my code currently looks like:

var data = {
  name: req.body.name,
  email: req.body.email,
  website: req.body.website,
  ...
  ...
}

var query = connection.query('INSERT INTO table_name SET ?', data)

Since SET isn't valid SQL, if I wanted to use Postgres, the query would look like this using the pg module:

client.query('INSERT INTO table_name (name, email, website) VALUES ($1, $2, $3)', req.body.name, req.body.email, req.body.website)

This would turn out to be very tedious considering that I have almost 40 fields.

Is there any better way to do this or am I stuck with having to write the query manually?

Thank you.

2 个答案:

答案 0 :(得分:4)

由于您已经有一个包含相关数据的对象

var data = {
  name: req.body.name,
  email: req.body.email,
  website: req.body.website,
  ...
  ...
}

您可以编写一个查询函数来包装pg客户端的query方法并添加对象值作为支持:

function insert(client, table, values) {
    const keys = Object.keys(values),
          // IMPORTANT: escape column identifiers. If `values` should come
          // from an uncontrolled source, naive concatenation would allow
          // SQL injection.
          columns = keys.map(k => client.escapeIdentifier(k)).join(', '),
          placeholders = keys.map((k, i) => '$' + (i + 1)).join(', ');

    return client.query(`INSERT INTO ${client.escapeIdentifier(table)} 
                         (${columns}) VALUES (${placeholders})`,
                        // According to docs `query` accepts an array of
                        // values, not values as positional arguments.
                        // If this is not true for your version, use the
                        // spread syntax (...args) to apply values.
                        keys.map(k => values[k]));
}

...

insert(client, 'table_name', data);

或者你可能会用sql-template-strings重写你的查询,这似乎相当不错。

答案 1 :(得分:1)

使用pg-promise时很容易实现,这里是完整的代码:

var pgp = require('pg-promise')();
var db = pgp(/*connection details*/);

app.get('/get', (req, res)=> {
    var insert = pgp.helpers.insert(req.body, null, {table: 'table_name'});
    db.none(insert)
        .then(()=> {
            // success
        })
        .catch(error=> {
            // error
        });
});

API:helpers.insertnone

方法helpers.insert可以为您生成完整的INSERT语句,格式正确。

它不仅是最简单的方法,而且也是最灵活的方法,因为您不需要更改任何内容来开始生成多插入语句,即insert方法的第一个参数是对象数组,您将获得多插入查询。

如果您只想要请求中的特定属性,那么最好的方法是单独指定它们,作为请求之外的ColumnSet(可重用,以获得最佳性能):

var cs = new pgp.helpers.ColumnSet(['name', 'email', 'website'], {table: 'table_name'});

app.get('/get', (req, res)=> {
    var insert = pgp.helpers.insert(req.body, cs);
    db.none(insert)
        .then(()=> {
            // success
        })
        .catch(error=> {
            // error
        });
});

返回新id-s

数组的示例

没有转化

app.get('/get', (req, res)=> {
    var insert = pgp.helpers.insert(req.body, cs) + 'RETURNING id';
    db.many(insert)
        .then(data=> {
            // success
        })
        .catch(error=> {
            // error
        });
});
带转化的

app.get('/get', (req, res)=> {
    var insert = pgp.helpers.insert(req.body, cs) + 'RETURNING id';
    db.map(insert, [], a=>a.id)
        .then(ids=> {
            // ids = array of id-s
        })
        .catch(error=> {
            // error
        });
});