MySQL: Get results.insertId ON DUPLICATE KEY UPDATE - mysql

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)`

Related

NodeJs/Express, MySQL - Retrieve array using array of another table

I have two tables: Tasks and Updates. The Tasks table contains ToDo items, while the Updates table contains updates on tasks sent by users. Updates are tied to tasks via a matching taskId value in each table. I have a set of queries that successfully pulls all the tasks matching the user's permissions (familyId) - what I need to do next is use the taskId column values pulled from the 2nd query resulting array to then complete a statement like
SELECT taskUpdate FROM updates WHERE taskId = ?
But I cannot figure out how to do this.
Here is what I currently have:
// Get all tasks
Task.getAll = (userId, result) => {
sql.query(`SELECT familyid FROM users WHERE id = '${userId}'`, (err, res) => {
if (err) {
console.log("Error selecting from USERS: ", err);
return result(null, err);
}
sql.query("SELECT * FROM tasks WHERE familyId = ?", res[0].familyid, (err, res) => {
if (err) {
console.log("Error selecting from TASKS: ", err);
return result(null, res);
}
console.log("tasks: ", res);
return result(null, res);
})
});
};
You can see in the second nested query that I retrieve all rows from "tasks" where familyId matches the result pulled from the first query. So I want to use the taskId column to now match to rows in the Updates table with the same taskId value. The trickiest thing for me is figuring out how to use the array from the 2nd query - I have a vague idea of using something like a foreach loop but have tinkered for a while with no luck.
ADDENDUM: By request, here is sample data:
TASKS table
taskId col: 200, 201...
taskName col: Test01, Test02...
UPDATES table
updateId: 1, 2...
taskId: 200, 201...
taskUpdate: "Checked garage", "Need to go to store"...
...There are more columns in each but the only columns that really matter here are taskId in each and taskUpdate in Updates.
After pulling the tasks in "SELECT * FROM tasks WHERE familyId = ?", we'll have an array of tasks. I need to use the taskId column values from that array and feed all resultant taskId values into "SELECT taskUpdate FROM updates WHERE taskId = ?" so that I can retrieve the taskUpdate values shown above.

MySQL query for filtering

I want to write a query in MySQL for filtering. For example, if there is a column id in table table1 where the filter values for id come in a POST request body, saved in variable A. I want to extract the matching rows if A is not empty and return all rows otherwise. I am not sure about using IN with WHERE.
SELECT * FROM table1 WHERE id IN (A)
One option is that I return all rows from the database and use JavaScript filters, but I don't want to return all rows and expose the entire table to user.
NOTE: A can be a single value, a tuple or an array.
If you use javascript, use A.join(), and sanitize your POST.
var your_post = [1, 2, 3];
var A = your_post.join();
if (A == '') {
var sql = 'SELECT * FROM table1';
con.query(sql, function (err, result) {
if (err) throw err;
console.log(result);
});
} else {
var sql = 'SELECT * FROM table1 WHERE id IN (?)';
con.query(sql, [A], function (err, result) {
if (err) throw err;
console.log(result);
});
}

Refer to another field value to affect a new one in MySQL w/Node.js

thanks for reading.
I have a table with 3 fields, one is the ID, which autoincrements and I can´t access it from my Node.js server since it's added by MySql. Another field contains a string, and the last field should be the sum of the 3 first letters of the string field, added to the id.
The thing is, when I do my query I can't just add them up because the id doesn´t exist until the query is sent to the DB.
What should I do? It'd be such an inconvenience to handle the ID autoincrement from the API.
Thanks for your time!
After you insert the row, you can get its ID and update the third column.
connection.query('INSERT INTO yourTable (name) VALUES (?)', [name], function(err, result) {
if (err) {
throw err;
}
let code = name.substr(0, 3) + result.insertId;
connection.query('UPDATE yourTable SET code = ? WHERE id = ?', [code, result.insertId], function(err) {
if (err) {
throw err;
}
});
});
However, this won't work if you're inserting multiple rows in bulk, since result.insertId is just the last row that was inserted.
You could update all the rows where the code
connection.query('INSERT INTO yourTable (name) VALUES ?', names.map(n => [n]), function(err, result) {
if (err) {
throw err;
}
connection.query('UPDATE yourTable SET code = CONCAT(SUBSTR(name, 1, 3), id) WHERE code IS NULL', function(err) {
if (err) {
throw err;
}
});
});

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.

putting vars in sql query

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.