I'm using NodeJS with MySQL and async/await statements. I've got a UNIQUE column in a MySQL table named audioid.
I need to check if an audioid exists. If so I need to update a row. If not I need to insert a row. I'm using MySQL's So here's the query;
try {
if(tag1){
row_b = await db.query( "SELECT tagid FROM tags WHERE tagname = ?", [tag1]);
if (row_b > 0){
const tagid1 = row_b[0].tagid;
console.log('tagid first = ' + tagid1);
row_c = await db.query(
"INSERT INTO entitytag (tagid1) VALUES (?) WHERE audioid = ?
ON DUPLICATE KEY UPDATE tagid1 = ?", [tagid1, audioid, tagid1]
);
}
else {
row_d = await db.query( 'INSERT IGNORE INTO tags (tagname) VALUES (?)', [tag1]);
const tagid1 = row_d.insertId;
console.log('tagid 2nd = ' + tagid1);
row_e = await db.query(
"INSERT INTO entitytag (tagid1) VALUES (?) WHERE audioid = ?
ON DUPLICATE KEY UPDATE tagid1 = ?", [tagid1, audioid, tagid1]
);
}
console.log('success!');
res.json('success!');
}
}
But there's the error in the console;
[ RowDataPacket { tagid: 11 } ]
tagid 2nd = 0
ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE audioid = 26 ON DUPLICATE KEY UPDATE tagid1 = 0' at line 1
INSERT INTO entitytag (tagid1) VALUES (?) WHERE audioid = ?
ON DUPLICATE KEY UPDATE tagid1 = ?
is wrong on a SQL basis since insert creates a new row, so there are no WHERE conditions applicable. If you want to specify that the duplicate check should happen on audioid then you should create an index on the table with UNIQUE attribute on that field.
The correct query (from an syntax standpoint only) is
INSERT INTO entitytag (tagid1) VALUES (?)
ON DUPLICATE KEY UPDATE tagid1 = ?
Without having sample data,expected results and table structures it is a matter of guessing but a working (functionally) query could be:
INSERT INTO entitytag (tagid1, audioid) VALUES (?,?)
ON DUPLICATE KEY UPDATE tagid1 = ?
Related
I'm using MySQL with NodeJS with asyncs and awaits. I'm trying to get the last insertid from my inserted row but keep getting errors.
Here's the async function;
function makeDb( config ) {
const connection = mysql.createConnection( config ); return {
query( sql, args ) {
return util.promisify( connection.query )
.call( connection, sql, args );
},
close() {
return util.promisify( connection.end ).call( connection );
}
};
}
And here's the code which is failing on the queries;
try {
if(tag1){
row_b = await db.query( "SELECT tagid FROM tags WHERE tagname = ?", [tag1]);
const onetagid1 = row_b[0].tagid;
console.log('onetagid1 = ' + onetagid1);
if (row_b > 0){
row_c = await db.query("
INSERT INTO entitytag (tagid1, audioid) VALUES (?,?)
ON DUPLICATE KEY UPDATE tagid1 = ?" [onetagid1, audioid, onetagid1]
);
} else {
row_d = await db.query( 'INSERT IGNORE INTO tags (tagname) VALUES (?)', [tag1]);
var twotagid1 = row_d.insertId;
console.log('twotagid1 2nd = ' + twotagid1);
row_e = await db.query(
"INSERT INTO entitytag (tagid1, audioid) VALUES (?,?)
ON DUPLICATE KEY UPDATE tagid1 = ?" [twotagid1, audioid, twotagid1]
);
}
res.json('json success!');
}
}
And here's the error;
onetagid1 = 30
twotagid1 2nd = 0
ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'I' at line 1
The error is twotagid1 2nd = 0 which should not be zero.
I'm not sure why this works when the other didn't. But I'll post it here hoping someone will be able to spot it;
try {
if(tag1){
row_c = await db.query( "SELECT tagid FROM tags WHERE tagname = ?", [tag1]);
if (row_c.length > 0){
console.log('tag exists in database ');
const tagid1 = row_c[0].tagid;
console.log('tagid1 = ' + tagid1);
row_f = await db.query(
"INSERT INTO entitytag (tagid1, audioid) VALUES (?,?)
ON DUPLICATE KEY UPDATE tagid1 = ?", [tagid1, audioid, tagid1 ]);
} else {
console.log('tag does not exist in database ');
row_d = await db.query( 'INSERT IGNORE INTO tags (tagname) VALUES (?)', [tag1]);
const tagInsertId = row_d.insertId;
console.log('tagInsertId = ' + tagInsertId);
row_e = db.query(
'INSERT INTO entitytag (tagid1, audioid) VALUES (?,?)
ON DUPLICATE KEY UPDATE tagid1 = ?', [tagInsertId, audioid, tagInsertId ]);
}
}
console.log('success!');
res.json(tag1);
}
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.
So, what am i doing wrong?
This query:
$query = "INSERT INTO table1 (art_nr, article, balance, list_type)
VALUES('$art_nr', '$article', '$balance', '$list_type')
ON DUPLICATE KEY UPDATE balance = sum(balance + '$quantity_ordered');
UPDATE table2 SET list = 'History' WHERE id = '$id'";
Will give me this error:
Failed to run query: SQLSTATE[HY000]: General error: 1111 Invalid use
of group function
This query:
$query = "INSERT INTO table1 (art_nr, article, balance, list_type) VALUES('$art_nr', '$article', '$balance', '$list_type')
ON DUPLICATE KEY UPDATE balance = sum(balance + '$quantity_ordered') WHERE art_nr = '$art_nr';
UPDATE table2 SET list = 'History' WHERE id = '$id'";
Will give me this error:
Failed to run query: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to
use near 'WHERE art_nr = 'S2Bygel'; UPDATE purchase_orderlist SET
list' at line 2
UPDATE
This was my first query. With Params:
//SECURITY
$params_array= array(
':id' => $_POST['formData']['id'],
':art_nr' => $_POST['formData']['art_nr'],
':article' => $_POST['formData']['article'],
':quantity_ordered' => $_POST['formData']['quantity_ordered'],
':list_type' => $_POST['formData']['list_type']
);
//QUERY
$query = "INSERT INTO table1 (art_nr, article, balance, list_type) VALUES (:art_nr, :article, :balance, :list_type)
ON DUPLICATE KEY UPDATE balance = balance + VALUES(:quantity_ordered) WHERE art_nr = :art_nr;
UPDATE table2 SET list = 'History' WHERE id = :id";
The problem with this query is that im running two querys at the same time. and then i will get this error:
Failed to run query: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
SUCCESS
I had to use prepared statements and separate my two querys:
//SECURITY
$params_array= array(
':art_nr' => $_POST['formData']['art_nr'],
':article' => $_POST['formData']['article'],
':quantity_ordered' => $_POST['formData']['quantity_ordered'],
':list_type' => $_POST['formData']['list_type']
);
//QUERY
$query = "INSERT INTO table1
(art_nr, article, balance, list_type)
VALUES (:art_nr, :article, :quantity_ordered, :list_type)
ON DUPLICATE KEY UPDATE
art_nr = art_nr, article = article, balance = balance + :quantity_ordered, list_type = list_type";
//EXECUTE
try{
$stmt = $db->prepare($query);
$result = $stmt->execute($params_array);
}
catch(PDOException $ex){
die("Failed to run query: " . $ex->getMessage());
}
//SECURITY
$params_array= array(
':id' => $_POST['formData']['id']
);
//QUERY
$query = "UPDATE table2 SET list = 'History' WHERE id = :id";
//EXECUTE
try{
$stmt = $db->prepare($query);
$result = $stmt->execute($params_array);
echo "success";
}
catch(PDOException $ex){
die("Failed to run query: " . $ex->getMessage());
}
You just want to add the value of $quantity_ordered to balance for the row? Then you don't need the sum() aggregation function. Just the + operator is enough.
But it seems like you're doing this in a host language like PHP. You should urgently learn to use parameterized queries! Do not use string concatenation (or interpolation) to get values in a query. That's error prone and may allow SQL injection attacks against your application.
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)`
I'm inserting a row into a MySQL database table. On the first insertion I want a new row to be added, but after that I just want that row to be updated. Here's how I'm doing it. An Ajax request calls the following php file:
<?php
include "base.php";
$bookID = $_POST['bookID'];
$shelfID = $_POST['shelfID'];
$userID = $_SESSION['user_id'];
$query = mysql_query("SELECT shelfID FROM shelves WHERE userID = '$userID' AND shelfID = '$shelfID' AND bookID = '$bookID'");
if (mysql_num_rows($query) == 0) {
$insert = "INSERT INTO shelves (bookID,shelfID,userID) VALUES ('$bookID','$shelfID','$userID')";
mysql_query($insert) or die(mysql_error());
} elseif (mysql_num_rows($query) == 1) { //ie row already exists
$update = "UPDATE shelves SET shelfID = '$shelfID' WHERE userID = '$userID' AND bookID = '$bookID'";
mysql_query($update) or die(mysql_error());
}
?>
As it stands it adds a new row every time.
You should consider using PDO for data access. There is a discussion on what you need to do here: PDO Insert on Duplicate Key Update
I'd flag this as duplicate, but that question is specifically discussing PDO.
You can use the INSERT ... ON DUPLICATE KEY UPDATE syntax. As long as you have a unique index on the data set (i.e. userid + shelfid + bookid) you are inserting, it will do an update instead.
http://dev.mysql.com/doc/refman/5.5/en/insert-on-duplicate.html