putting vars in sql query - mysql

New to Node development.
How do you put a variable in a sql query for the VALUES part. Here is what I have. Let me know if it will work.
let email = req.body.email;
let number = req.body.number;
var sql = "INSERT INTO userdata (email, number) VALUES (email, number)";
Thanks
Also, second question. is there anyway I can check if a record already exists with the same email or number within the one sql statement.

According documentation, You should to use parametrized query like:
const email = req.body.email;
const number = req.body.number;
const sql = "INSERT INTO userdata (email, number) VALUES (?, ?)";
connection.query(sql, [ email, number ],
function (err, results) {
}
);
About second question: If you want to your table will have unique records fro each email/number pair you should to add unique index based on those fields.

Related

Nodejs | add table columns and values conditionally in sql query statment

I want to simplify my mysql queries. Here is my current query where I need to include columns conditionally and so there values:
const hasPassword = false;
const myEmail = xyz#yopmail.com;
const myPassword = 123456;
query("SELECT id, name, email, status, (hasPassword ? 'password ,' : '') FROM users WHERE email=${myEmail} (hasPassword ? 'AND password=${myPassword}' : '')"
How to write simplified query similar to the below format:
query("SELECT id, name, email FROM users email=? AND password=?",[email, password]);

How can I INSERT if row doesn't exist, else UPDATE that row?

At the front-end, whenever I press submit an answer to a question, it'll create 1 result_ID that has these columns.
result_ID is auto-increment, question_ID is relation with the same question_ID from questions table.
If it's the first time the user chooses the answer, it'll create an answer_result (i parse in answer_ID) and answer_checkResult (value 1 or 0 to identify it's correct or incorrect), and a history_ID to identify each record separately.
History_ID is a different table that has the quiz_ID (to identify topic) and user_ID
example: History_ID 221 has 4 questions in there, and has 4 answers with 4 answer_result.
What I don't know is how can I create a situation if the row doesn't exist, it'll run INSERT INTO situation, and else if it already exists (because the user can change the answer multiple times in 1 question), it'll UPDATE. I've just created only the INSERT INTO option, but I don't know how to do the update in this model at the same time with INSERT INTO.
This is my history_result.model that I've created, I don't know how to create an if-else to update and create at the same time...
history_result.model
const HistoryResult = function (history_result) {
this.question_ID = history_result.question_ID;
this.answer_result = history_result.answer_result;
this.answer_checkResult = history_result.answer_checkResult;
this.history_ID = history_result.history_ID;
};
HistoryResult.create = async (newHistoryResult, result) => {
await db.query(
`INSERT INTO history_result SET question_ID = ?, answer_result = ?, answer_checkResult = ?, history_ID = ?`,
[
newHistoryResult.question_ID,
newHistoryResult.answer_result,
newHistoryResult.answer_checkResult,
newHistoryResult.history_ID,
],
(err, data) => {
if (err) {
result(err, null);
return;
} else {
return result(null, data);
}
}
);
};
And here's how I create the history_result controller
const HistoryResult = require("../models/history_result.model");
exports.createHistoryResult = async (req, res) => {
let { history_ID } = req.params;
let { question_ID, answer_result, answer_checkResult } = req.body;
let historyResult = new HistoryResult({
question_ID: question_ID,
answer_result: answer_result,
answer_checkResult: answer_checkResult,
history_ID: history_ID,
});
HistoryResult.create(historyResult, (err, data) => {
if (err) {
res.status(500).send({
message: err.message || "Error while creating result",
});
}
res.send(data);
});
};
Is there anyways I can achieve this? Thanks.
Yes, you can.
but first you have to make question_ID as PRIMARY KEY. And second parameter that you pass to db.query is object that contains history_result's attributes
INSERT INTO history_result
SET ?
ON DUPLICATE KEY UPDATE
answer_result = VALUES(answer_result),
answer_checkResult = VALUES(answer_checkResult),
history_ID = VALUES(history_ID)
db.query(query, objectHere, (err, data) => {
if (err) {
result(err, null);
return;
} else {
return result(null, data);
}
}))
First, please read the MySQL Insert or Update on duplicate-key update tutorial,
or this Official MySQL INSERT ... ON DUPLICATE KEY UPDATE Statement document
Now back to your question. As I understand, the question_ID and history_ID pair in the history_result table would be unique, as each user will only give one answer to a question in a quiz.
First you would need to create a unique index constraints of the pair (question_ID, history_ID) of your table.
ALTER TABLE history_result
ADD CONSTRAINT uc_question_history
UNIQUE (question_ID,history_ID);
And then issue an INSERT ON DUPLICATE KEY UPDATE statement to achive the effect.
INSERT INTO history_result
(
question_ID, answer_result, history_ID
)
VALUES
(14, 21, 12)
ON DUPLICATE KEY UPDATE
answer_result = 21;
If the question_ID = 14 and history_ID = 12 row already existed (scenario that user has already answer this question), it will trigger to update the answer_result. If not, it will insert a new record.
The DUPLICATE KEY constraint is met if a new row is a duplicate in UNIQUE index or PRIMARY KEY. In our case, it's the unique index of (question_ID, history_ID), hence the UPDATE statement will be invoked.

Mysql: which fields matched using "OR"

I have this query:
SELECT * FROM accounts WHERE username = "aaa" OR email = "abc#example.com" OR mobile = "123456789"
I can find which field did match like this:
var username = req.body.username;
var email = req.body.email;
var mobile = req.body.mobile;
database.query("SELECT * FROM accounts WHERE username = ? OR email = ? OR mobile = ?",[username, email, mobile, (err, result)=>{
if (result.username == username) {...}
if (result.email == email) {...}
if (result.mobile == mobile) {...}
}
But, I'd like to know which field did match without using if multiple times (if possible). So, is that possible form within Mysql only?
You can put it in the SELECT list. You can use CONCAT_WS() to combine the list of columns into a comma-separated list. It will omit NULL values, so this will just list the matched fields.
database.query(`SELECT *,
CONCAT_WS(',',
IF(username = ?, 'username', NULL),
IF(email = ?, 'email', NULL),
IF(mobile = ?, 'mobile', NULL)) AS matched_fields
FROM accounts WHERE username = ? OR email = ? OR mobile = ?`, [username, email, mobile, username, email, mobile], (err, result) => {
var matched = result.matched_fields.split(',');
matched.each(field => {
switch(field) {
case 'username': ...; break;
case 'email': ...; break;
case 'mobile': ...; break;
});
})
Create custom column in select query and that custom column has case statement with three column(username, email, mobile) matching and print respective flag in that custom column to let it know that row comes from based on which condition.
Try Below:-
SELECT * FROM accounts WHERE (username = "aaa" OR email = "abc#example.com" OR mobile = "123456789")
Whichever field has first match then your condition become true and it will return result. If you want to match all the condition then you should use AND operator

MySQL: Get results.insertId ON DUPLICATE KEY UPDATE

I am developing an application that downloads images and their tags. When a download starts the program retrieves the tags and inserts them into the database. Here I am trying to insert a new tag and then create a relationship between the the tag and its download. The combination of name and type in tag is unique.
let download_id = 1;
let tag = {type:'language', name:'english'}
let sql = `INSERT INTO tag (name, type) SELECT '${tag.name}', id FROM tag_type WHERE type='${tag.type}' ON DUPLICATE KEY UPDATE count = count + 1, id=LAST_INSERT_ID(id)`
mysqlConnection.query(sql, (err, results) => {
if (err) throw err;
let sql = `INSERT INTO download_tag ?`;
mysqlConnection.query(sql, [{download_id: download_id, tag_id: results.insertId}], err => {
if (err) throw err;
});
});
However my first query returns this error Uncaught Error: ER_NON_UNIQ_ERROR: Column 'id' in field list is ambiguous I am unsure why my code is not working, it is very similar to the accepted answer in this question.
Your problem is that LAST_INSERT_ID doesn't know whether you are referring to id from the tag table or from the tag_type table. You just need to qualify the field name with its table:
let sql = `INSERT INTO tag (name, type)
SELECT '${tag.name}', id FROM tag_type WHERE type='${tag.type}'
ON DUPLICATE KEY UPDATE count = count + 1, id=LAST_INSERT_ID(tag.id)`

Connection issue while trying run my mysql query via nodejs

I have a query and I am trying to run the query. The issue i think is that i have added a condition where an item from a column from the database must equal to the computer name of the user.
Hence, I created a variable called computerName that simply retrieves the host name of the computer via NodeJs.
var os = require("os");
var computerName = os.hostname(); // Detect the computer name associated with the tablet
Below is the query
connection.query("SELECT box_id, longestDimension from box where longestDimension != '' AND LOWER(box_id) = LOWER(computerName)", function(err, rows, fields) {
computerName seems to be the problem because when the query is run with a generic name such as box45 it works.
I am getting connection error. I guess the better question is how do I include a defined variable into the query
It looks like you're trying to insert computerName directly into your SQL statement. At minimum, you'd need to write something like
connection.query("SELECT box_id, longestDimension from box where longestDimension != '' AND LOWER(box_id) = LOWER('" + computerName + "')", function(err, rows, fields) {
But you should be escaping the value of computerName. You don't know what value it might contain.
connection.query("SELECT box_id, longestDimension from box where longestDimension != '' AND LOWER(box_id) = LOWER('" + connection.escape(computerName) + "')", function(err, rows, fields) {
But a better way to do it is with ? substitution:
connection.query("SELECT box_id, longestDimension from box where longestDimension != '' AND LOWER(box_id) = LOWER(?)", computerName, function(err, rows, fields) {
Also, if the collation of the box_id column is case insensitive, which is usually the default, then you can skip the lowercasing the values.
I'd write it like this, for readability
let sql = "SELECT box_id, longestDimension FROM box WHERE longestDimension != '' AND box_id = ?";
connection.query(sql, computerName, function(err, rows, fields) {
Or if your node version supports template literals
let sql = `SELECT box_id, longestDimension
FROM box
WHERE longestDimension != ''
AND box_id = ?`;
connection.query(sql, computerName, function(err, rows, fields) {
If you have multiple variables there's two ways to do it: with an object, or with an array.
Object method:
let payload = {
box_id: "Johannesburg",
longestDimension: 12.4
};
let sql = 'INSERT INTO box SET ?';
connection.query(sql, payload, function(err, rows, fields) {
});
Array method:
let computerName = "Johannesburg";
let longestDimension = 12.4;
let sql = 'INSERT INTO box SET box_id = ?, longestDimension = ?';
// alternative, equivalent SQL statement:
// let sql = 'INSERT INTO box (box_id, longestDimension) VALUES (?, ?)';
connection.query(sql, [ computerName, longestDimension ], function(err, rows, fields) {
});
You can even combine them
let payload = {
box_id: "Johannesburg",
longestDimension: 12.4
};
let boxName = "Box A";
let sql = 'UPDATE box SET ? WHERE box_name = ?';
connection.query(sql, [ payload, boxName ], function(err, rows, fields) {
});
In this last example, the payload object is substituted for the first ? and the boxName variable is substituted for the second ?.