I'm trying to upsert a database table with loopback. The raw query is
insert into all_inventory (sku, qty, regal, fach, skuRegalFach)
values (?, 1, ?, ?, ?)
on duplicate key update
qty = qty + 1,
regal = values(regal),
fach = values(fach)
Is there any way to do this with loopback?
Currently I'm facing two problems.
I get:
ER_DUP_ENTRY: Duplicate entry '22323' for key
'all_inventory_SkuRegalFach_uindex'
Because loopback doesn't seem to be able to handle the key correctly.
And I have no idea how to tell loopback to add 1 to the qty field instead of just overriding it with the new value.
I have it working with a raw query right now,
let ds = Inventory.dataSource,
values = [sku, regal, fach, sku + regal + fach],
sql = `insert into all_inventory (sku, qty, regal, fach, skuRegalFach) values (?, 1, ?, ?, ?) on duplicate key update qty = qty + 1, regal = values(regal), fach = values(fach)`
ds.connector.query(sql, values, (err, products) => {
if (err) return console.error(err);
cb(null, products);
});
Is there a way to do this with loopback's ORM?
I'd use a find filter. Either findById or find with an appropriate filter.
If you get a result, then it exists. You can modify qty and then store it. If it doesn't exist, then you just create it.
I am trying to execute 2 queries.
First one should insert data (especially "product") or update in case the db already has a row with such title.
Second one should insert new category for product which was inserted\updated from 1st query and ignore any inserts, if table already has such product with such category
Here is my code :
conn = DatabaseConnection.getConnection();
stmt = conn.createStatement();
conn.setAutoCommit(false);
String updateSQL = "INSERT INTO product (title, price, `status`) " +
"VALUES(?, ?, ?)" +
"ON DUPLICATE KEY UPDATE price = ?, `status` = ?;"
PreparedStatement preparedStatement = conn.prepareStatement(updateSQL);
preparedStatement.setString(1, product.getTitle());
preparedStatement.setBigDecimal(2, product.getPrice());
preparedStatement.setInt(3, product.getStatus().ordinal());
preparedStatement.executeUpdate();
updateSQL = "INSERT IGNORE INTO product_categories (product_id, category_id) " +
"VALUES (last_insert_id(), ?);";
preparedStatement = conn.prepareStatement(updateSQL);
preparedStatement.setLong(1, categoryId);
preparedStatement.executeUpdate();
conn.commit();
So, the problem is that I use last_insert_id() which means that i will use incorrect row in 2nd query if 1st query just updated the data.
So, I would like to know how could I synchronize these 2 queries.
Since you don't have access to last_insert_id() in the second query, you'll have to fetch it as in the answers for this question.
Here's an example:
...
preparedStatement.executeUpdate(); // this is the first query
ResultSet rs = preparedStatement.getGeneratedKeys();
if ( rs.next() )
{
long last_insert_id = rs.getLong(1);
updateSQL = "INSERT IGNORE INTO product_categories (product_id, category_id) " +
"VALUES (?, ?);";
preparedStatement = conn.prepareStatement(updateSQL);
preparedStatement.setLong(1, last_insert_id);
preparedStatement.setLong(2, categoryId);
preparedStatement.executeUpdate();
}
conn.commit();
If the first query didn't result in an INSERT, then there isn't enough information to add the product to the product_category, in which case this is skipped all together. This does assume that the product is already in the category. If you're not sure about that, and want to execute the second query regardless, you could query for the product_id:
SELECT id FROM product WHERE title = ?
and then use that id instead of the last_insert_id variable, or, you could change the second query and use title as a key (although I'd stick with an id):
INSERT IGNORE INTO product_categories (product_id, category_id)
VALUES (SELECT id FROM product WHERE title = ?), ?)
I have table - config.
Schema:
config_name | config_value
And I would like to update multiple records in one query. I try like that:
UPDATE config
SET t1.config_value = 'value'
, t2.config_value = 'value2'
WHERE t1.config_name = 'name1'
AND t2.config_name = 'name2';
but that query is wrong :(
Can you help me?
Try either multi-table update syntax
UPDATE config t1 JOIN config t2
ON t1.config_name = 'name1' AND t2.config_name = 'name2'
SET t1.config_value = 'value',
t2.config_value = 'value2';
Here is a SQLFiddle demo
or conditional update
UPDATE config
SET config_value = CASE config_name
WHEN 'name1' THEN 'value'
WHEN 'name2' THEN 'value2'
ELSE config_value
END
WHERE config_name IN('name1', 'name2');
Here is a SQLFiddle demo
You can accomplish it with INSERT as below:
INSERT INTO mytable (id, a, b, c)
VALUES (1, 'a1', 'b1', 'c1'),
(2, 'a2', 'b2', 'c2'),
(3, 'a3', 'b3', 'c3'),
(4, 'a4', 'b4', 'c4'),
(5, 'a5', 'b5', 'c5'),
(6, 'a6', 'b6', 'c6')
ON DUPLICATE KEY UPDATE id=VALUES(id),
a=VALUES(a),
b=VALUES(b),
c=VALUES(c);
This insert new values into table, but if primary key is duplicated (already inserted into table) that values you specify would be updated and same record would not be inserted second time.
in my case I have to update the records which are more than 1000, for this instead of hitting the update query each time I preferred this,
UPDATE mst_users
SET base_id = CASE user_id
WHEN 78 THEN 999
WHEN 77 THEN 88
ELSE base_id END WHERE user_id IN(78, 77)
78,77 are the user Ids and for those user id I need to update the base_id 999 and 88 respectively.This works for me.
instead of this
UPDATE staff SET salary = 1200 WHERE name = 'Bob';
UPDATE staff SET salary = 1200 WHERE name = 'Jane';
UPDATE staff SET salary = 1200 WHERE name = 'Frank';
UPDATE staff SET salary = 1200 WHERE name = 'Susan';
UPDATE staff SET salary = 1200 WHERE name = 'John';
you can use
UPDATE staff SET salary = 1200 WHERE name IN ('Bob', 'Frank', 'John');
maybe for someone it will be useful
for Postgresql 9.5 works as a charm
INSERT INTO tabelname(id, col2, col3, col4)
VALUES
(1, 1, 1, 'text for col4'),
(DEFAULT,1,4,'another text for col4')
ON CONFLICT (id) DO UPDATE SET
col2 = EXCLUDED.col2,
col3 = EXCLUDED.col3,
col4 = EXCLUDED.col4
this SQL updates existing record and inserts if new one (2 in 1)
Camille's solution worked. Turned it into a basic PHP function, which writes up the SQL statement. Hope this helps someone else.
function _bulk_sql_update_query($table, $array)
{
/*
* Example:
INSERT INTO mytable (id, a, b, c)
VALUES (1, 'a1', 'b1', 'c1'),
(2, 'a2', 'b2', 'c2'),
(3, 'a3', 'b3', 'c3'),
(4, 'a4', 'b4', 'c4'),
(5, 'a5', 'b5', 'c5'),
(6, 'a6', 'b6', 'c6')
ON DUPLICATE KEY UPDATE id=VALUES(id),
a=VALUES(a),
b=VALUES(b),
c=VALUES(c);
*/
$sql = "";
$columns = array_keys($array[0]);
$columns_as_string = implode(', ', $columns);
$sql .= "
INSERT INTO $table
(" . $columns_as_string . ")
VALUES ";
$len = count($array);
foreach ($array as $index => $values) {
$sql .= '("';
$sql .= implode('", "', $array[$index]) . "\"";
$sql .= ')';
$sql .= ($index == $len - 1) ? "" : ", \n";
}
$sql .= "\nON DUPLICATE KEY UPDATE \n";
$len = count($columns);
foreach ($columns as $index => $column) {
$sql .= "$column=VALUES($column)";
$sql .= ($index == $len - 1) ? "" : ", \n";
}
$sql .= ";";
return $sql;
}
Execute the code below to update n number of rows, where Parent ID is the id you want to get the data from and Child ids are the ids u need to be updated so it's just u need to add the parent id and child ids to update all the rows u need using a small script.
UPDATE [Table]
SET column1 = (SELECT column1 FROM Table WHERE IDColumn = [PArent ID]),
column2 = (SELECT column2 FROM Table WHERE IDColumn = [PArent ID]),
column3 = (SELECT column3 FROM Table WHERE IDColumn = [PArent ID]),
column4 = (SELECT column4 FROM Table WHERE IDColumn = [PArent ID]),
WHERE IDColumn IN ([List of child Ids])
Execute the below code if you want to update all record in all columns:
update config set column1='value',column2='value'...columnN='value';
and if you want to update all columns of a particular row then execute below code:
update config set column1='value',column2='value'...columnN='value' where column1='value'
Assuming you have the list of values to update in an Excel spreadsheet with config_value in column A1 and config_name in B1 you can easily write up the query there using an Excel formula like
=CONCAT("UPDATE config SET config_value = ","'",A1,"'", " WHERE config_name = ","'",B1,"'")
INSERT INTO tablename
(name, salary)
VALUES
('Bob', 1125),
('Jane', 1200),
('Frank', 1100),
('Susan', 1175),
('John', 1150)
ON DUPLICATE KEY UPDATE salary = VALUES(salary);
UPDATE 2021 / MySql v8.0.20 and later
The most upvoted answer advises to use the VALUES function which is now DEPRECATED for the ON DUPLICATE KEY UPDATE syntax. With v8.0.20 you get a deprecation warning with the VALUES function:
INSERT INTO chart (id, flag)
VALUES (1, 'FLAG_1'),(2, 'FLAG_2')
ON DUPLICATE KEY UPDATE id = VALUES(id), flag = VALUES(flag);
[HY000][1287] 'VALUES function' is deprecated and will be removed in a future release. Please use an alias (INSERT INTO ... VALUES (...) AS alias) and replace VALUES(col) in the ON DUPLICATE KEY UPDATE clause with alias.col instead
Use the new alias syntax instead:
official MySQL worklog
Docs
INSERT INTO chart (id, flag)
VALUES (1, 'FLAG_1'),(2, 'FLAG_2') AS aliased
ON DUPLICATE KEY UPDATE flag=aliased.flag;
just make a transaction statement, with multiple update statement and commit. In error case, you can just rollback modification handle by starting transaction.
START TRANSACTION;
/*Multiple update statement*/
COMMIT;
(This syntax is for MySQL, for PostgreSQL, replace 'START TRANSACTION' by 'BEGIN')
Try either multi-table update syntax
Try it copy and SQL query:
CREATE TABLE #temp (id int, name varchar(50))
CREATE TABLE #temp2 (id int, name varchar(50))
INSERT INTO #temp (id, name)
VALUES (1,'abc'), (2,'xyz'), (3,'mno'), (4,'abc')
INSERT INTO #temp2 (id, name)
VALUES (2,'def'), (1,'mno1')
SELECT * FROM #temp
SELECT * FROM #temp2
UPDATE t
SET name = CASE WHEN t.id = t1.id THEN t1.name ELSE t.name END
FROM #temp t
INNER JOIN #temp2 t1 on t.id = t1.id
select * from #temp
select * from #temp2
drop table #temp
drop table #temp2
UPDATE table name SET field name = 'value' WHERE table name.primary key
If you need to update several rows at a time, the alternative is prepared statement:
database complies a query pattern you provide the first time, keep the compiled result for current connection (depends on implementation).
then you updates all the rows, by sending shortened label of the prepared function with different parameters in SQL syntax, instead of sending entire UPDATE statement several times for several updates
the database parse the shortened label of the prepared function , which is linked to the pre-compiled result, then perform the updates.
next time when you perform row updates, the database may still use the pre-compiled result and quickly complete the operations (so the first step above can be omitted since it may take time to compile).
Here is PostgreSQL example of prepare statement, many of SQL databases (e.g. MariaDB,MySQL, Oracle) also support it.
I would like to only insert or update a row, if the following SELECT returns a 0 or no rows.
SELECT (value = ? AND status = ? AND connected = ?)
FROM channels, data
WHERE data.channel_id = channels.channel_id AND channels.channel_name = ? AND sample_time < ?
ORDER BY sample_time DESC
LIMIT 1
Basically, it is a data archiver that only writes changes. That is it only writes data for a given sample_time, if the data is not the same as what was written for the previous sample_time. This SELECT gets the data for a given channel for the previous sample_time and compares it to the data that has come along for the current sample_time. So if this returns 0, that is the data is different, it should go ahead and write it. And if no data has been written for this channel yet, then it should return no rows, and the new data should be written. The following is my query for writing the data:
INSERT INTO data (acquire_time, sample_time, channel_id, value, status, connected)
SELECT ?, ?, channels.channel_id, ?, ?, ?
FROM channels
WHERE channel_name = ?
ON DUPLICATE KEY UPDATE acquire_time = ?, value = ?, status = ?, connected = ?
New data for the current sample_time may overwrite previous data for the current sample_time using the ON DUPLICATE KEY UPDATE, just not if it is the same as the data stored for the previous sample_time.
The duplicate key is the combination of the channel_id and sample_time. There is also a unique index on the channel_id and acquire_time.
Thank you for your time.
After your clarifications below, I believe this will do what you want:
INSERT INTO data (acquire_time, sample_time, channel_id, value, status, connected)
SELECT ?, ?, channels.channel_id, ?, ?, ?
FROM channels
WHERE channel_name = ?
AND NOT EXISTS (
SELECT 1
FROM (
SELECT value, status, connected
FROM channels, data
WHERE data.channel_id = channels.channel_id AND channels.channel_name = ?
AND sample_time < ?
ORDER BY sample_time DESC
LIMIT 1
) a
WHERE a.value = ? and a.status = ? and a.connected = ?
)
ON DUPLICATE KEY UPDATE acquire_time = ?, value = ?, status = ?, connected = ?;