MySQL update without primary key - mysql

i'm looking to figure out how i can update a row like a LIMIT 2,2 on a select
there is a little example:
col1 | col2
5 10
5 10
5 10
I want to update the 2nd row like this:
col1 | col2
5 10
1 10
5 10
i know the row number so i want something like that:
UPDATE table
SET col1 = 1
WHERE col1 = 5
LIMIT 2, 1
we cant use limit but i know this is achievable, HeidiSQL can do it and i'm trying to figure out how they are doing
thanks

If you need to update particular rows, you need a column or columns that can be used as primary key.
SQL works on sets of rows and you can only update rows that can be identified as belonging to the set.
For example, you can
UPDATE Customers SET Preferred=True WHERE TotalSales > 1000
which will set the "Preferred" flag for any customers that have sales over 1000. This might be one customer or a million or none.
The only way to do the single row update you asked about is to have some way to identify the row. In many database servers you can configure an IDENTITY or SEQUENCE column that will auto-assign each row a unique ID.
You can add an ID column with the IDENTITY property set, which would get you:
ID | col1 | col2
1 5 10
2 5 10
3 5 10
So updating that particular row would be:
UPDATE table SET col1 = 1 WHERE ID = 2

Related

How to get different auto_increment value depending on value of different key

I have a table set up for todo items, the main columns are hash and owner. I would like to have it set up in a way where hash auto increments based on the value of owner and if a value was deleted all the hash values would automatically update with new incremented values.
Say there were 3 users, for simplicity I'll set their IDs in owner as 1, 2 and 3. Each one has 3 items, the table would look like this
hash owner
1 1
2 1
3 1
1 2
2 2
3 2
1 3
2 3
3 3
If I was to add a new entry for owner 1 it would auto increment the hash to 4 creating a table like this
hash owner
1 1
2 1
3 1
4 1
1 2
2 2
3 2
1 3
2 3
3 3
Then, if I ran DELETE FROM todo WHERE hash = 2 AND owner = 1 the hashes for entries linked to owner 1 would change to 1 | 2 | 3 rather than being 1 | 3 | 4
If I then added a new user with INSERT INTO todo SET owner = 4 they would get their own "set of hashes".
Is this at all possible or am I asking for too much?
The only reason I would like do this is so each user can have their own easy to remember hashes rather than something like jIUxdi3XjaDv
You can create an ordinary auto increment column in the table.
CREATE TABLE elbat
(ordinal integer
NOT NULL
AUTO_INCREMENT,
owner integer,
UNIQUE (ordinal));
If you want you can make it the primary key of the table too instead of just declaring it unique.
Then use a view that calculates the hash by counting the occurrences of that auto increment column, that are less than or equal to the current one.
CREATE VIEW weiv
AS
SELECT (SELECT count(*)
FROM elbat t2
WHERE t2.owner = t1.owner
AND t2.ordinal <= t1.ordinal) hash,
t1.owner
FROM elbat t1;
db<>fiddle
In versions of MySQL that support row_number() (version 8.0 and above) instead of the subquery row_number() can be used in the view.
CREATE VIEW weiv
AS
SELECT row_number() OVER (PARTITION BY t1.owner
ORDER BY t1.ordinal) hash,
t1.owner
FROM elbat t1;

Run UPDATE query by a custom order

Is there a way to update all records in the table by a specific custom order? I specifically mean a situation, when the actual order comes from the 'outside' (eg as POST value).
For example, have a table
id | title | order_idx
----------------------
1 | lorem | 1
2 | ipsum | 2
3 | dolor | 3
I have a form that submits a hidden field, carrying ID values in this order: 2, 3, 1
I want to update the table to add incremental number to order_idx in each next row, going by the ID order served by the form field. So in this case, end result should look like this:
id | title | order_idx
----------------------
1 | lorem | 3
2 | ipsum | 1
3 | dolor | 2
Can this be done in a single UPDATE query somehow as opposed to running 3 queries (each including WHERE clause) in a php loop
You can use conditional expressions in assignment statements, like so:
UPDATE t
SET x = CASE
WHEN 2 THEN 1
WHEN 3 THEN 2
WHEN 1 THEN 3
ELSE x
WHERE ....
parameterized:
UPDATE t
SET x = CASE
WHEN ? THEN 1
WHEN ? THEN 2
WHEN ? THEN 3
ELSE x
WHERE ....
In either case, the query will most likely need constructed dynamically to account for a varying number of items to order.
Since your comment indicates potentially hundreds...
MySQL has a limit to query length (reference).
For a large number, I would start recommending a different approach.
Step 1) CREATE TEMPORARY TABLE `newOrder` (id INT, new_order_idx INT);
Step 2) INSERT id's and their new order into the temp table.
Step 3) UPDATE t INNER JOIN newOrder AS n ON t.id = n.id SET t.order_idx = n.new_order_idx WHERE ...
Step 4) DROP TEMPORARY TABLE newOrder;
The process itself is no longer a single query; but the UPDATE is.
Note: If you have a unique key involving order_idx I am entirely sure either of these would work. Occasions when I have needed to maintain uniqueness, the usual solution is to shift the records to be adjusted to a completely different range in one step, and then to their new positions in a second one. (Something like UPDATE t SET order_idx = -1 * order_idx WHERE ... would work as a pre-Step 3 range shift in the second part of this answer.)
Use ON DUPLICATE KEY UPDATE like below:
INSERT INTO table (id, order_idx) VALUES (1,3),(2,1),(3,2)
ON DUPLICATE KEY UPDATE order_idx=VALUES(order_idx);
So you can set order_idx dynamically for every row:
INSERT INTO table (id, order_idx)
VALUES (1,order_list[0]),(2,order_list[1]),(3,order_list[2])
ON DUPLICATE KEY UPDATE order_idx=VALUES(order_idx);

How to copy one column's value to another before updating

I am runnning a Postgres and Mysql server and I have table:
id | name | age | old_age
1 abc 20
I want to update column age with 21 with storing old value 20 into old_age column.
I can fetch the row and read the value of age and then update but that will require running 2 queries. 1 select and 1 update. Is there any way we can update in 1 query? I just want to copy age to old_age.
Just do
UPDATE TableName SET old_age=age, age=21 WHERE

How to delete specific values from table

I have the following table structure:
table "sample"
objectID | objectValues
1 | 5,6,7
2 | 6,7,5,8
3 | 5
4 | 7,8,9,5,6
5 | 10,11
6 | 5
So, I want to delete all ",5" or "5," values from "objectValues" and delete all columns which theirs "objectValues" value is only "5". How can I do this?
You can try a tricky method using four queries to make this change.
first query for delete all rows when object value is 5
DELETE FROM sample WHERE objectValues = 5;
second for update rows when is a value is in all places except first and last
UPDATE sample
SET objectValues = REPLACE(objectValues , ',5,', ',');
third when the value 5 is on the first place
UPDATE sample
SET objectValues = LEFT(objectValues, LENGTH(objectValues)-2)
WHERE objectValues LIKE '5,%';
and last query when the value 5 is on the last place
UPDATE sample
SET objectValues = RIGHT(objectValues, LENGTH(objectValues)-2)
WHERE objectValues LIKE '%,5';
Try this
delete from table where find_in_set(5,objectValues)>0;

MySQL Trigger Sum Two Columns where userID is the same

I have the following product table
id | companyID | prodID | price | stock | stockAvailable | sumStock
1 A 2 10 5 4
2 B 2 50 10 5
I need to have a trigger when I update a product row that will update the sumStock.
I am new to Triggers, my attempt failed:
CREATE TRIGGER `SalesDB`.`stockSumUpdate` BEFORE UPDATE
ON SalesDB.Product FOR EACH ROW
BEGIN
SET Product.sumStock = Product.stock + Product.stockAvailable
END
My Goal is in this case to calculate the SUM(stock) AS stockSum Where ProductID=2
in this case that would be 15 and then add that to the sumStock. Then add the stockAvailable column to that as well. So in sumStock for both collumns I would have 24.
Result would be:
id | companyID | prodID | price | stock | stockAvailable | sumStock
1 A 2 10 5 4 29
2 B 2 50 10 5 29
Try this syntax:
CREATE TRIGGER `SalesDB`.`stockSumUpdate` BEFORE UPDATE
ON SalesDB.Product FOR EACH ROW
BEGIN
SET NEW.sumStock = NEW.stock + NEW.stockAvailable
END;
That adds within a row of a table.
To get the total, you would use something like:
CREATE TRIGGER `SalesDB`.`stockSumUpdate` BEFORE UPDATE
ON SalesDB.Product FOR EACH ROW
BEGIN
SET NEW.sumStock = (select sum(stock + stockAvailable)
from products where p.prodid = new.prodid and p.id <> id
) + NEW.stock + NEW.stockAvailable;
END;
Except, this still, doesn't do what you want. If you are updating multiple rows at a time, you will get different total stock values.
In other words, you are trying to update a group of rows whenever you update a single row. Gosh, when put like that, it doesn't seem like a good idea. The second set of udpates could update even more rows and so on and so on (it wouldn't happen because of the product).
Instead, create a table with product as a primary key and the stock available in that table (might be an existing table). Then update the summary table every time there is a change in this table.