How to insert two table in one time?
I need to insert second table user_information the field user_id with first table user insert returning id, I found this answer but I can't find how to be with params prepared statements
var dbQuery = 'WITH insertUser AS (
INSERT INTO "user" (status, create_date) VALUES ($1, $2) RETURNING id
)
, insertUserInformation AS (
INSERT INTO user_information (user_id, email) VALUES ($3, $4)
)
';
yield queryPromise(dbClient, dbQuery, [status, timestamp, ??, email]);
pg
Use transactions. That way either all queries will be committed, or none will be committed. And the incomplete state before you have executed all queries is not visible for other processes.
More on how to do transactions in node-postgres is available at https://github.com/brianc/node-postgres/wiki/Transactions
And for reference the most relevant section is:
var Client = require('pg').Client;
var client = new Client(/*your connection info goes here*/);
client.connect();
var rollback = function(client) {
//terminating a client connection will
//automatically rollback any uncommitted transactions
//so while it's not technically mandatory to call
//ROLLBACK it is cleaner and more correct
client.query('ROLLBACK', function() {
client.end();
});
};
client.query('BEGIN', function(err, result) {
if(err) return rollback(client);
client.query('INSERT INTO account(money) VALUES(100) WHERE id = $1', [1], function(err, result) {
if(err) return rollback(client);
client.query('INSERT INTO account(money) VALUES(-100) WHERE id = $1', [2], function(err, result) {
if(err) return rollback(client);
//disconnect after successful commit
client.query('COMMIT', client.end.bind(client));
});
});
});
It's impossible in postgresql. I solved exact the same problem by creating function and simply executing with parameters. As I see in your table structure, you don't have many attributes, so this will be relatively easy.
Example code:
function.sql
CREATE OR REPLACE FUNCTION createSomething
(
IN attr1 VARCHAR(20),
IN attr2 VARCHAR(200)
)
RETURNS void AS $$
DECLARE userId INTEGER;
BEGIN
INSERT INTO table1 (col1, col2) VALUES
(
attr1,
attr2
) RETURNING id INTO userId;
INSERT INTO table2 (user_id, col11, col2) VALUES
(
userId,
col11,
col12
);
END;
$$ LANGUAGE plpgsql;
Usage:
SELECT createSomething('value1', 'value2');
Please notice, that second insert statement will know what was recently user's id and will use it.
PostgreSQL Prepared Statements will not let you do it. You will have to use a transaction.
Below is your example implemented with pg-promise, using ES7 syntax:
const pgp = require('pg-promise')({
// initialization options;
});
const db = pgp(/* your connection object or string */);
db.tx(async t => {
const user = await t.one('INSERT INTO user(status, create_date) VALUES($1, $2) RETURNING id', [status, timestamp]);
return t.none('INSERT INTO user_information(user_id, email) VALUES($1, $2)', [user.id, email]);
})
.then(() => {
// SUCCESS;
})
.catch(error => {
// ERROR;
});
I do not believe this can be accomplished as a natural sql statement. You have to wrap it up as a procedure or some other mechanism.
Related
I have a table with different post categories and I want to get the categories ID from the name. Example name: random => id: 1.
I got the variable like this:
const { name, title, cat, con, user_file } = req.body;
console.log(cat); //returnes the name as it should
This is my query:
var sql = "SELECT id FROM cat WHERE cat_name = ?";
db.query(sql, cat, function(err, result) {
if(!result){
return next();
}
const cat_id = result[0];
});
If I than try to console.log the cat_id I get undefined. I have tried doing this in many different way but it comes out the same every time. If I just run
SELECT id FROM cat WHERE cat_name = random
in thee database manager it works like it should and returnes the ID.
Edit: The purpose is to get the id to insert a foreign key into another table.
Your results is an empty array. This is (assuming you're using the mysql package) because your function call is incorrect.
When passing arguments to your query, as explained here, you need to pass an array of values, not just a single value. For example:
connection.query('SELECT * FROM `books` WHERE `author` = ?', ['David'], function (error, results, fields) {
// error will be an Error if one occurred during the query
// results will contain the results of the query
// fields will contain information about the returned results fields (if any)
});
In your case, that means you're looking for cats where the name is the first character of cat (e.g. cat[0]).
It ended up being a problem with variables only being saved in the query level. It console.logged the right number inside the db.query and the wrong one out of the db.query. So the solution for now is to put it inside I guess.
My solution now looks like this:
exports.post = (req, res, next) => {
let { cat } = req.body;
let cat_id = 0;
db.query(
"SELECT id FROM cat WHERE cat_name = ?",
[cat],
async function (err, results) {
if (!err) cat_id = results[0].id;
else console.log(err);
db.query(
"INSERT INTO posts SET ?",
{ cat_id: cat_id },
(error, results) => {
if (error) console.log(error);
else res.status(200).redirect("/post");
}
);
}
);
};
I am building a REACT note taking app.
I only track the changes the user makes to the note, and not what the current state of the note is.
If there are no changes to a specific property, the property will be sent as an empty string.
I am handling this in NODE (node-postgres) with the following function:
const updateNote = async (req, res) => {
const { category, title, body, nid } = req.body;
let noteStatement = "";
let valueStatement = "";
for (const key in req.body)
{
if (req.body[key] !== "" && key !== "nid") {
noteStatement = noteStatement + key + ", ";
valueStatement = valueStatement + `'${req.body[key]}', `;
}
}
try {
const result = await pool.query(
`UPDATE notes SET (${noteStatement}last_updated)
= (${valueStatement}(to_timestamp(${Date.now()} / 1000.0)))
WHERE nid = ${nid} RETURNING *`
);
const note = result.rows;
return res.status(200).send({ note });
} catch (err) {
return res.send({error: err});
}
};
I may be overthinking, but the goal was to send the smallest bit of data to the DB as possible.
I have spent a fair amount of time on this and this is the most pragmatic approach I came up with.
Is writing this type of query bad practice?
Would it make more sense to send all the note data including properties that have not been updated from React and have a fixed query updating all properties?
EDIT: Updated Query
const updateNote = async (req, res) => {
const { category, title, body, nid } = req.body;
const text = `UPDATE notes SET (category, title, body, last_updated)
= ($1, $2, $3, (to_timestamp(${Date.now()} / 1000.0)))
WHERE nid = $4 RETURNING *`;
const values = [category, title, body, nid];
try {
const result = await pool.query(text, values);
const note = result.rows;
return res.status(200).send({ note });
} catch (err) {
return res.send({ error: err });
}
};
I wanted to leave a comment but soon realized I approach the character limit so I would just leave it as a response.
First of, I want to make sure I understand what you are trying to accomplish. I assume you just wanna update your DB with only the fields that has been provided from the client. With that in mind I just want to underline the fact that most people are trying to overcomplicate things that should not. Everything in software is a tradeoff, in your case your data isn't that big to worry about updating just certain fields. It can be done but not the way you are doing it right now, you can have a utility function that would build a parameterized query based on the values that are not empty/null depending on how would you send the data that did not change from the client
Which brings me to the 2nd thing, you should never write a SQL query the way you have done it, by concatonating a string, leaves you vulnerable to SQL injections. Instead you must always use parameterized query unless you use some kind of library that abstracts writing the queries (ORMs).
As a sidenote, never trust data that comes from the client, so always, always validate the data on the server before you make any changes to the DB, even if you already did validation on the client. You can do it using a middleware like celebrate or other validation libraries. Never trust anything that comes from the client.
SECOND EDIT
The issue was caused by the MAX_INTEGER_VALUE which is lower then the integer value I was passing. I changed the MySQL table column to TEXT instead of BIGINT and everything is being returned correctly.
Thanks for all the help!
EDIT
So I just realized that the userID variable and the guildID variables are being passed using this line of code.
mysqlModule.userCrewSearch(575783451018526744, 282997056438665217);
However the values that are being supplied to the SQL statement turn the last two digits of the number into '00'. So instead of 575783451018526744 the value being passed into the SQL statement is 575783451018526700.
So why is this value being changed when nothing I am doing in my code is changing these values?
Original Post
I'll keep this short and sweet. I'm trying to run a query using the nodejs MySQL package. I'm not sure where I'm going wrong but whenever I call my function that executes my query, I'm always returned an empty array, unless I hardcode the values into the SQL query.
Heres the code:
// Search for the User's Crew
function userCrewSearch(guildID, userID) {
pool.getConnection(function(err, connection) {
if(err) {
return console.log(err);
}
var sql = "SELECT * FROM `crew-members` WHERE `userID`=? AND `guildID`=?;";
console.log(sql);
connection.query(sql, [guildID, userID], function(err, results) {
connection.release(); // always put connection back in pool after last query
if(err) {
return console.log(err);
}
return console.log(results);
});
});
}
I'm calling this function like so: userCrewSearch(575783451018526744, 282997056438665217);
Both of the values I'm passing are integers. However this is what I get in my console.
However, here is my code with the values hardcoded into the SQL... to which the code then returns the result in the form of a RowDataPacket.
// Search for the User's Crew
function userCrewSearch(guildID, userID) {
pool.getConnection(function(err, connection) {
if(err) {
return console.log(err);
}
var sql = "SELECT * FROM `crew-members` WHERE `userID`=282997056438665217 AND `guildID`=575783451018526744;";
console.log(sql);
connection.query(sql, [guildID, userID], function(err, results) {
connection.release(); // always put connection back in pool after last query
if(err) {
return console.log(err);
}
return console.log(results);
});
});
}
Heres the result.
Bonus Question: How do I handle the RowDataPacket? Can I convert this directly into an object so I can call results.crewID and return just that value?
Same problem i was facing few days ago. I have solved this by converting the parameters into string.
function userCrewSearch(String(guildID), String(userID)) {
// your code here
}
Try adding + before your numeric parameter, it converts into number, it worked for me-
connection.query(sql, [+guildID, +userID], function(err, results) {
for your bonus questions answer, you can directly access the crewID or some other key using,
results[0].crewID
or do something like -
const [ result ] = results;
console.log(result.crewID)
I am writing code in conjunction with sql on node js.
I want to load the data according to the condition, and I want to dynamically get the condition depending on the variable.
Here is the current code:
db.all ("select CollectionID, CollectionName from Collection where
CollectionID = abc", function () {
How do I want to receive data according to the variable abc ?
abc's value is number .
var abc = 1;
var query = 'select CollectionID, CollectionName from Collection where CollectionID = ?'
db.all (query, [abc], function (err, rows) {
if (err) throw err;
console.log(rows);
});
i need to do a multiple row delete query with the where clause in list (id1,id2..)
But since we don't have lists in JS i'm having a problem with passing the parameters to the query.This is my code:
let list =[1,2,..];
let Query = 'DELETE FROM Table WHERE id IN (?)';
connection.query(Query,list, function (err, result) {
`enter code here`
};
when i pass it this way and after logging the mysql server to a Logfile i see that it actually passes only the first id.
PS : i tried without the parentheses around ? and also doing a Array.join on the list but both didn't work.
Read in document of https://github.com/mysqljs/mysql#performing-queries (if you use this lib to connect mysql)
let list =[1,2,..];
let Query = 'DELETE FROM Table WHERE id IN (?)';
// values param need is a array of value to binding to "?"
// you can try [list.toString()] if the block above not working
connection.query(Query,[list], function (err, result) {
`enter code here`
};
Simply append the list of items to the query string:
let list = [1, 2, 3];
let Query = `DELETE FROM Table WHERE id IN (${list})`;
connection.query(Query, function (err, result) {
`enter code here`
};
Unfortunately, ? placeholders don't work with the IN operator. So you should escape the values. Say the list variable is coming from an external source; so to prevent SQL Injection you can:
// `list` is filled in outside this process
const Query = `DELETE FROM Table WHERE id IN (${list.map((item) => connection.escape(item))})`;
connection.query(Query, function (err, result) {
// handle error or result here
};
I noticed that list.map(connection.escape) won't work and throw:
TypeError: Cannot read property 'config' of undefined