How can I do own increment value in mysql - mysql

I'm struggling to do proper sql script to increment field on specific way.
Those two script are without any exception, but nothing happened on the results.
Script 1:
UPDATE
myTable T1,
(
SELECT id,
(#s:=#s+1) AS seq
FROM myTable, (SELECT (#s:=0) AS s ) s
WHERE infotext IS NULL ORDER BY grouptext
) T2
SET sequence = seq
WHERE T1.id = T2.id
Script 2:
UPDATE myTable AS target
INNER JOIN (
SELECT supfault_id,
(#s:=#s+1) AS seq
FROM myTable, (SELECT (#s:=0) AS s ) s
WHERE infotext IS NULL ORDER BY grouptext
) AS ordered ON ordered.id = target.id
SET sequence = seq

This one get the last desc value from table1 and increment by one then update the table2:
set #inc = 0;
select cast(valToIncrement as signed) into #inc from
(select REPLACE(fkid,' ','') as valToIncrement from tbl_1 ORDER BY fkid)as a ORDER BY valToIncrement desc limit 1;
update tbl_2 set fkid = #inc + 1 where fkid = 122;

Subqueries working well separately, so I wondered why I can't update my sequence value by seq from subquery.
I'm not expert, but I felt that need to be used some virtual table for my subquery.
Here is solution for inner join case:
CREATE TEMPORARY TABLE supportGroupSeqcalculation AS
SELECT supfault_id,
(#s:=#s+1) AS seq
FROM myTable, (SELECT (#s:=0) AS s ) s
WHERE infotext IS NULL
ORDER BY grouptext;
UPDATE myTable AS target
INNER JOIN supportGroupSeqcalculation AS ordered ON ordered.supfault_id = target.supfault_id
SET sequence = seq;
DROP TEMPORARY TABLE supportGroupSeqcalculation;
We can get into temporary table specific order and record it as sequence value.
It is not necessarily to drop temporary table, it exists only in current session.

Related

How do I get the rows from sql select to use them afterwards in the same transaction?

Suppose we are doing a SELECT and UPDATE in the same commit in mysql (MariaDB). How can I do:
SELECT id from my_table WHERE mycondition LIMIT 20 FOR UPDATE;
UPDATE my_table SET column1 = 0 WHERE id = the result of the previous select
COMMIT
where id is a primary key auto increment column.
EDIT: I understand that doing like this I would get the result of the SELECT printed, no? At least is what I wanted too, to know which rows I modified
This does not work:
-- UPDATE my_table
-- SET column1 = 0
-- WHERE id in (SELECT id from my_table WHERE mycondition LIMIT 20)
edited:
SELECT #IDS:= GROUP_CONCAT(id)
FROM my_table
WHERE mycondition
LIMIT 20;
UPDATE my_table
SET column1 = 0
where FIND_IN_SET(id,#IDS);
SELECT #IDS;
I would phrase this as a single update join:
UPDATE my_table t1
INNER JOIN
(
SELECT id
FROM my_table
ORDER BY <something>
LIMIT 20
) t2
ON t2.id = t1.id
SET
column1 = 0;
Note that using LIMIT without ORDER BY is fairly undefined and meaningless. If you want to select 20 records using LIMIT, it should be with respect to a certain ordering of your table.

How to use OR in query with priority?

In a simple query like
SELECT *
FROM table
WHERE id='x' OR id='y'
How to give a priority to get only one of the WHERE clauses?
I mean getting rows with id='x'. Only if there is no row, get row with id='y'.
In other words, do not use id='y' if there is a row for id='x'.
If you want only one row, the simplest method is limit:
SELECT t.*
FROM table t
WHERE id IN ('x', 'y')
ORDER BY (id = 'x') DESC
LIMIT 1;
The id = 'x' in the order by uses the fact that MySQL treats boolean values as integers in a numeric constant. So "true" is treated as 1 and "false" as 0. The DESC puts the true values (i.e. 'x') first.
If there are multiple possible rows that could be returned, then NOT EXISTS is a possibility:
select t.*
from t
where t.id = 'x' or
(t.id = 'y' and
not exists (select 1 from t t2 where t2.id = 'x')
);
In MySQL, this version might be optimized better using union all, if you have an index on id:
select t.*
from t
where t.id = 'x'
union all
select t.*
from t
where t.id = 'y' and
not exists (select 1 from t t2 where t2.id = 'x');
Here is another way to fetch same data with help the Rank basis, And it's support multiple values as well as, based on your select statement.
SELECT TOP 1 *, (RANK() OVER (ORDER BY VAL DESC )) AS RANK_N FROM TEST_TABLE T WHERE T.ID IN('X','Y') ORDER BY RANK_N
You can use case statement or limit clause. Limit clause is the better option. Do not forget to use order by while using limit clause
select * from
(SELECT *
FROM table
WHERE id='x' OR id='y')
where
case when id = 'x' then id = 'x'
when id = 'Y' then id = 'Y' end ;
SELECT * FROM table WHERE id='x' OR id='y' order by id limit 1;

Update table with random values from another table without duplicates in MySQL

I want to update a column in a MySQL table that contains string values with values from another table that contains unique names, but without repeating the same values.
Each name in the 'names' table has a unique id from 1 - 1001.
There are 161 names in the target table.
I tried something like this, but it fetches duplicate entries:
UPDATE table_to_update
SET name =
( SELECT name FROM `names`
WHERE id >= (SELECT FLOOR(RAND()*(SELECT MAX(id) FROM `names`)) )
LIMIT 1 ) ;
Here is one option if you are using MySQL 8+, which supports ROW_NUMBER:
UPDATE table_to_update t1
INNER JOIN
(
SELECT id, ROW_NUMBER() OVER (ORDER BY id) rn
FROM table_to_update
) t2
ON t1.id = t2.id
INNER JOIN
(
SELECT name, ROW_NUMBER() OVER (ORDER BY id) rn
FROM (SELECT name, id FROM names ORDER BY RAND() LIMIT 161) t
) t3
ON t2.rn = t3.rn
SET
t1.name = t3.name;
Note that I hard-coded the LIMIT value to be 161 in the subquery, given that you know the size of the target table. This value could be made dynamic as well, but would require more work.

How to DELETE the NEXT row values that is going to match the PREVIOUS row values base on a 2 column in MySQL

I need help and I want to know, if how can I delete the next row or column values that matches the previous row or column values on a MySQL table base from a 2 columns.
So, if the next row/column values/result contains the same values on the previous rows/columns values/result it will be deleted, but if the next column didn't match both of the previous column values/result, that row should not be deleted. What will be the right query for that condition?
I'm trying to make a select query first, to verify the data and this is my query for the select. Is my query right for the select?
SELECT current_row.row, current_row.id, current_row.column1,
current_row.column2, previous_row.row, previous_row.id,
previous_row.column1, previous_row.column2
FROM
(SELECT #rownum:=#rownum+1 row, a.*
FROM MyTable a, (SELECT #rownum:=0) r
ORDER BY unix_time, id
) as current_row
LEFT JOIN
(SELECT #rownum2:=#rownum2+1 row, a.*
FROM MyTable a, (SELECT #rownum2:=0) r
ORDER BY unix_time, id) as previous_row
ON (current_row.id = previous_row.id)
AND (current_row.column1 = previous_row.column1)
AND (current_row.column2 = previous_row.column2)
AND (current_row.row = previous_row.row - 1)
LIMIT 10;
Thank you very much in advance for any help!
Cheers!
We're trying to select data with assigned new virtual id for comparing, so ON clause should be t1.myid=t2.myid+1 and WHERE clause should filter col1 and col2 rows:
SET #id1:=0 , #id2:=0 ;
SELECT * FROM (
(SELECT *, #id1:=#id1+1 as myid from mytable ) as t1
LEFT JOIN
(SELECT *, #id2:=#id2+1 as myid from mytable ) as t2
ON t1.myid = t2.myid + 1
)
WHERE t1.col1= t2.col1 and t1.col2 = t2.col2
And for DELETE command, you should save results in temporary table and then delete rows where their id is stored in temp table:
SET #id1:=0 , #id2:=0 ;
CREATE TEMPORARY TABLE tbl_ids AS
SELECT t1.id FROM ( -- t1.id returns NEXT row
(SELECT *, #id1:=#id1+1 as myid from mytable ) as t1
LEFT JOIN
(SELECT *, #id2:=#id2+1 as myid from mytable ) as t2
ON t1.myid = t2.myid + 1 -- t1.myid > t2.myid
)
WHERE t1.col1= t2.col1 and t1.col2 = t2.col2 ;
DELETE FROM mytable WHERE id in (SELECT * FROM tbl_ids) ;

How to shuffle id in my MySQL table permanently in place?

I have a simple table with following structure and a lot of rows:
id | name | title |
------------------------------
Need to replace id with other value, in other words I need to permanently shuffle my table. What query do I need to run? This query I need to run exactly one time... no matter how long time or memory it will take.
Considering your rows size is 800, you may do something like bellow:
Create a Temporary Table with all record of your table.
e.g. CREATE TABLE TMP_TABLE (SELECT * FROM YOUR_TABLE).
DROP TABLE YOUR_TABLE; .
CREATE TABLE YOUR_TABLE (SELECT * FROM TMP_TABLE ORDER BY RAND() )
DROP TABLE TMP_TABLE; .
The following query should do that following:
The whole id set will be same as before, just shuffle the ids;
tbl is the one to update
tbl2 generates a random row_num for tbl
tbl3 generates a random (different to above) row_num for tbl3
with tbl2.row_num1 = tbl3.row_num2, the shuffle is done
UPDATE tbl INNER JOIN
(SELECT *, (#rm1 := #rm1 + 1) as row_num1 FROM tbl CROSS JOIN (SELECT #rn1 := 0) param ORDER BY RAND()) tbl2
ON tbl.id = tbl2.id
INNER JOIN
(SELECT *, (#rm2 := #rm2 + 1) as row_num2 FROM tbl CROSS JOIN (SELECT #rn2 := 0) param ORDER BY RAND()) tbl3
ON tbl2.row_num1 = tbl3.row_num2
SET tbl.id = tbl3.id;
You could use database VIEW for your purpose using shuffle logic
Otherwise use another table to backup current table and then SELECT shuffle rows from the backup table. Then TRUNCATE the your table and then insert shuffle rows from select query of backup table.