Updating two fields in the same query using the same calculated value - mysql

I have the following query to update a table where the field is calculating as a rank based on a score field.
update `table` T1 set Rank=
(select count(*)+1 from (select * from `table` WHERE platform='asdf') T2
WHERE T2.score > T1.score AND T2.platform='asdf') WHERE T1.platform='asdf'
However, I want to set a difference field from the old rank which uses the previous rank to calculate (rankDiff=rank - f) where
f = ` (select count(*)+1 from (select * from `table` WHERE platform='asdf') T2
WHERE T2.score > T1.score AND T2.platform='asdf') WHERE T1.platform='asdf'`
Does anybody know a way I can do this? I was thinking of joining the table with the information but I can't get the JOIN ON part right with the count calculation (possible?).
Anyone have any ideas how this can be done without just straight up duplicating the code (which is an option, but not an elegent one!).

is this what you are trying to achieve:
update `table` T1 set Rank=(select count(*)+1 from (select * from `table`
WHERE platform='asdf') T2
WHERE T2.score > T1.score AND T2.platform='asdf') WHERE T1.platform='asdf' as NewRankew),
RankDiff=Rank-NewRank

Related

Using group by in SET clause

I'm trying to update a column of a table so that is equal to the count of something in another table. Like this:
UPDATE TABLE
SET TOTAL = (SELECT COUNT(f1)
FROM TABLE2
GROUP BY f2);
But I keep getting sub query returns more than 1 row, and I can't think of how to fix it.
UPDATE (copied from the comment)
f2 is the relation between TABLE and TABLE2 – Thomasd d
Based on your comment
f2 is the relation between TABLE and TABLE2
you probably want something like this
UPDATE TABLE T1, (SELECT f2, COUNT(F1) cnt FROM TABLE2 GROUP BY f2) T2
SET T1.TOTAL = T2.cnt
WHERE T1.f2=T2.f2
adapt T1.f2 if necessary
UPDATE t1
SET total = ( SELECT COUNT(f1)
FROM t2
WHERE t1.f2 = t2.f2 );
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=91de17deff657f66fa54b42fe20ed3c5
Add WHERE total IS NULL if you do not need to recalculate values for rows which have a value already.
Your subquery is returning multiple values and your SET statement is only expecting one. This might fix your code if that is what you are looking for.
UPDATE TABLE
SET TOTAL = (SELECT COUNT(f1)
FROM TABLE2)

MySQL update subquery can't specify table target issue

I have been going through many queries, but can't seem to find the right combination to get this to work. I get the error "You can't specify target table 't1' for update in FROM clause". I know MySQL doesn't like the subquery in the update statement and have read about wrapping it in other select statements, but can't seem to figure it out. Here is a stripped down query of what I am looking for:
UPDATE myTable t1 SET t1.num=concat(t1.num,'B') WHERE t1.num in ('1','2') and t1.expiry=(SELECT max(t2.expiry) from myTable t2 where t2.num=t1.num);
Basically trying to get the latest date (expiry) for each number (num) and change the number where applicable.
This should works :
UPDATE myTable t1, (SELECT num, max(expiry) expiry from myTable t2 group by num) t2
SET t1.num = concat(t1.num,'B')
WHERE t1.num in ('1','2')
and t1.expiry = t2.expiry
and t1.num = t2.num;

Turning a duplicate selection into an update

I've managed to select the count and IDs of each record that has duplicates via:
select T1.ID,T2.Count
from MyTable T1
join (SELECT ID,Count(*) as Count FROM MyTable
where Field_C=X
and Field_S=Y
group by NumberField,NameField having count(*)>1) T2
on T1.NumberField=T2.NumberField
and T1.NameField = T2.NameField
This returns the ID of the records I want to update (T1.ID) and the value I want to update a CountField with (T2.Count).
Just unsure how to change into update after getting this far.
If you have the select you have already the update this way
UPDATE MyTable T1
join (SELECT ID,Count(*) as Count FROM MyTable
SET T1.ID = T2.Count
where Field_C=X
and Field_S=Y
group by NumberField,NameField having count(*)>1) T2
on T1.NumberField=T2.NumberField
I guess a long day at the office but this solved it pretty easily. I think having the first select threw me off until I realized I needed to get rid of it entirely as I was not selecting but updating:
Update MyTable T1
join (SELECT ID,Count(*) as Count FROM MyTable
where Field_C=X
and Field_S=Y
group by NumberField,NameField having count(*)>1) T2
on T1.NumberField=T2.NumberField
and T1.NameField = T2.NameField
Set T1.CountField=T2.Count

mysql check if column values that are incremented by one have missing ones

I have a column in which I insert values incremented by one (the column is NOT AUTO_INCREMENT). How can I search for gaps in it, for instance the column goes: 1,2,4,5,6 - I want to select that missing 3. Thanks!
Simple case: only first gap
You can do that with:
SELECT
MIN(seq)
FROM
(SELECT
sequence,
#seq:=#seq+1 AS seq
FROM
t CROSS JOIN (SELECT #seq:=0) AS init) AS gap
WHERE
sequence!=seq
-here field sequence is pointing to your column, where you're looking for gap. See fiddle demo
Now, common case.
You can not use just JOIN or something like this, since size of your table may be lesser than possible gap in it. Imagine the situation, when your table is filled with only minimum and maximum value. For example, 1 and 10 - and you want to get all rows, so result will be sequence 1, 2, ... , 10. No matter how you will JOIN your table with itself, you will only get two rows - because only those two exist in your table. UNION is also not an option - since if we'll build that for 10, in common case that can be 100, 1000, e t.c. So for common case you have to create sequence table and fill it with values from MIN(sequence) and MAX(sequence) - and then, using LEFT JOIN, do like:
SELECT
full_table.sequence
FROM
full_table
LEFT JOIN t
ON full_table.sequence=t.sequence
WHERE
t.sequence IS NULL
Thats the statement I use for those tasks. id represents the field which you want to analyze.
SELECT t1.id+1 AS 'start_seq',
MIN(t2.id) - 1 AS 'end_seq'
FROM yourTable AS t1,
yourTable AS t2
WHERE t1.id < t2.id
GROUP BY t1.id
HAVING 'start_seq' < MIN(t2.id);
Though this one gets the job done, there might be better and more compact solutions out there.
You can try something like this
SELECT (t1.id + 1) as gap_starts_at,
(SELECT MIN(t3.id) -1 FROM your_table t3 WHERE t3.id > t1.id) as gap_ends_at
FROM your_table t1
WHERE NOT EXISTS (SELECT t2.id FROM your_table t2 WHERE t2.id = t1.id + 1)
HAVING gap_ends_at IS NOT NULL
try this!!
DECLARE #a int
SET #a = SELECT MIN(num) FROM table1
WHILE (SELECT MAX(num) FROM table1 ) > #a
BEGIN
IF #a NOT IN ( SELECT num FROM table1 )
PRINT #a
SET #a=#a+1
END

Selecting maximum column and row id

Is there a way to tell MySQL that while making something like this
SELECT id, MAX(seq) FROM t1 GROUP BY ident;
I can also get the id value? I know I shouldn't be using id if it's not in a group by but I feel like its strange to make a multi pass to get the row ids with the maximum seq field when it already passed it. So what is the most effective way to do this? id is the primary key
SELECT a.*
FROM tableName
INNER JOIN
(
SELECT ident, MAX(seq) seq
FROM tableName
GROUP BY ident
) b ON a.ident = b.ident AND
a.seq = b.seq
Mabye:
SELECT MAX(a.seq), (SELECT id FROM t1 as b where b.ident=a.ident AND MAX(a.seq) = b.seq LIMIT 1) as id FROM t1 AS a GROUP BY a.ident;
Fiddle
Try using self-join:
SELECT t1.* FROM MyTable t1
JOIN
(SELECT ident, MAX(seq) AS MAX_Seq
FROM MyTable
GROUP BY ident
) t2
ON t1.seq = t2.MAX_Seq
AND t1.ident = t2.ident
See this sample SQLFiddle
What is seq exactly ?
I guess you can also order your results ?
SELECT id FROM t1 GROUP BY ident ORDER BY seq DESC
Regarding to the others answer, seq is in another table ?