Update table set same value to all rows with duplicate value - mysql

I have a table of sport results. When using following code, the table get places according to the times.
SET #pos := 0;
UPDATE table SET Place = ( SELECT #pos := #pos + 1 ) ORDER BY Time ASC;
In case of same times (like rows 1,3 and 4,5), it updates it according to the ID-s, so the result is following:
ID | Time | Place
1 | 00:12:14 | 1
2 | 00:12:18 | 3
3 | 00:12:14 | 2
4 | 00:12:25 | 4
5 | 00:12:25 | 5
How could I update the table so, that if there is multiple rows of same time, all rows would get the best place (like in following table)?
ID | Time | Place
1 | 00:12:14 | 1
2 | 00:12:18 | 3
3 | 00:12:14 | 1
4 | 00:12:25 | 4
5 | 00:12:25 | 4

You can do it with a join of the table to a query returning for each row the number of rows less than its Time:
update tablename t inner join (
select t.id, (
select count(*) counter from tablename
where time < t.time
) counter
from tablename t
) c on c.id = t.id
set t.place = c.counter + 1;
See the demo.
Results:
| ID | Time | Place |
| --- | -------- | ----- |
| 1 | 00:12:14 | 1 |
| 2 | 00:12:18 | 3 |
| 3 | 00:12:14 | 1 |
| 4 | 00:12:25 | 4 |
| 5 | 00:12:25 | 4 |

Related

Counting and limiting number of rows per field value not working

I'm trying to limit the number of rows per field value of a given query. I've found this answered question:
here
As in the first answer of the link, I've created the following table:
create table mytab (
id int not null auto_increment primary key,
first_column int,
second_column int
) engine = myisam;
Inserted this data:
insert into mytab (first_column,second_column) values
(1,1),
(1,4),
(2,10),
(3,4),
(1,4),
(2,5),
(1,6);
And finally run this query
select
id,
first_column,
second_column,
row_num
from
(select
*,
#num := if(#first_column = first_column, #num + 1, 1) as row_num,
#first_column:=first_column as c
from mytab
order by first_column,id) as t,
(select #first_column:='',#num:=0) as r;
But instead of getting this result, where the row_num increases whenever first_column is repeated,
+----+--------------+---------------+---------+
| id | first_column | second_column | row_num |
+----+--------------+---------------+---------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 4 | 2 |
| 5 | 1 | 4 | 3 |
| 7 | 1 | 6 | 4 |
| 3 | 2 | 10 | 1 |
| 6 | 2 | 5 | 2 |
| 4 | 3 | 4 | 1 |
+----+--------------+---------------+---------+
I get this result:
+----+--------------+---------------+---------+
| id | first_column | second_column | row_num |
+----+--------------+---------------+---------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 4 | 1 |
| 5 | 1 | 4 | 1 |
| 7 | 1 | 6 | 1 |
| 3 | 2 | 10 | 1 |
| 6 | 2 | 5 | 1 |
| 4 | 3 | 4 | 1 |
+----+--------------+---------------+---------+
I literally copied the code from the link. I checked in SQL Fiddle and code works fine. I'm using XAMPP. Could that be the reason? If it is, is there any workaround to get something like the above working?
I'd really appreciate some help. Thanks in advance.
The variable assignment has to be in the sub-query.
select
id,
first_column,
second_column,
row_num
from
(select
m.*,
#num := if(#first_column = first_column, #num + 1, 1) as row_num,
#first_column:=first_column as c
from mytab m
cross join (select #first_column:='',#num:=0) r --this was in the outer query previously
order by first_column,id
) t

SQL insert into select with parameter for using with event scheduler

Hello I would like to make event for my application that works by insert new 3 record for 1 userID every midnight so the quantity of rows must have
n x 3 n is userIDs
+---------+-----------+-------+------------+------+----------+-------------+-------+
| userID | userNAME | chaID | chaNAME | goal | gender | row_number | dummy |
+---------+-----------+-------+------------+------+----------+-------------+-------+
| 1 | Nanyang | 1 | blahblah | 1 | 2 | 1 | 1 |
| 1 | Nanyang | 21 | something | 1 | 2 | 2 | 1 |
| 1 | Nanyang | 2 | anything | 1 | 2 | 3 | 1 |
| 2 | Julie | 3 | x | 2 | 1 | 1 | 2 |
| 2 | Julie | 12 | y | 2 | 1 | 2 | 2 |
| 2 | Julie | 23 | z | 2 | 1 | 3 | 2 |
| 3 | Kingkong | 4 | a | 1 | 2 | 1 | 3 |
| 3 | Kingkong | 5 | b | 1 | 2 | 2 | 3 |
| 3 | Kingkong | 6 | c | 1 | 2 | 3 | 3 |
+---------+-----------+-------+------------+------+----------+-------------+-------+
the row_number will be looped until they're <= 3
from my written ..
set #num := 0, #type := ‘';
CREATE TABLE random
as
(
SELECT
*
FROM (
select userID,userNAME, chaID, chaNAME,goal,gender,
#num := if(#type = userID, #num +1,1) as row_number,
#type := userID as dummy
from userchar
order by userID
) as x where x.row_number <= 3)
Anyway I used to try to create table with Select the first/least/max row per group in SQL
and it works very well and get the result like i shown. then I need to insert into in event instead of create table so i got this code below.. because I can't use SET #parameterfor insert
INSERT INTO random(userID, userNAME, chaID, chaNAME, goal, gender,row_number,dummy,status)
select *
from (select userID, userNAME, chaID, chaNAME, goal, gender,
(#num := if(#type = userID, #num +1,1)
) as row_number,
userID as dummy,
#stat as status
from hb_usercha u cross join
(select #type = '', #num := 0, #stat := '') params
order by userID,rand()
)
where row_number <= 3;
and this is a result what I got
+---------+-----------+-------+------------+------+----------+-------------+-------+
| userID | userNAME | chaID | chaNAME | goal | gender | row_number | dummy |
+---------+-----------+-------+------------+------+----------+-------------+-------+
| 1 | Nanyang | 1 | blahblah | 1 | 2 | 1 | 1 |
| 1 | Nanyang | 21 | something | 1 | 2 | 1 | 1 |
| 1 | Nanyang | 2 | anything | 1 | 2 | 1 | 1 |
| 1 | Nanyang | 3 | s | 2 | 1 | 1 | 1 |
| 1 | Nanyang | 12 | o | 2 | 1 | 1 | 1 |
| 1 | Nanyang | 23 | m | 2 | 1 | 1 | 1 |
| 1 | Nanyang | 4 | e | 1 | 2 | 1 | 1 |
| 2 | Julie | 5 | xoxo | 1 | 2 | 1 | 2 |
| 2 | Julie | 6 | xxx | 1 | 2 | 1 | 2 |
+---------+-----------+-------+------------+------+----------+-------------+-------+
.
.
.
.
It seems row_number loop isn't working
And I have no idea what's happening
Both code are same just changed parameters path
So It would be very good if someone can explain to me
Thank you so much
Assuming you want to do it for all users exists in user_char table.
Using Union all to get 3 records of each user and store the result in temporary table.
DELIMITER $$
CREATE EVENT `event_run_midnight` ON SCHEDULE EVERY 24 HOUR STARTS '2016-02-09 00:00:00' ON COMPLETION NOT PRESERVE ENABLE DO
BEGIN
drop temporary table if exists temp_users_1;
create Temporary table temp_users_1
select users.*,#row_num:=#row_num+1 as row_num,userID as dummy
from(
select * from user_char
union all
select * from user_char
union all
select * from user_char
) as users,(select #row_num:=0) as row_number
order by UserID;
/*
Copy temp table data to other temp table as MySQL
not allows to use same temp table in single query.
*/
drop temporary table if exists temp_users_2;
create Temporary table temp_users_2
select * from temp_users_1;
-- final query which returns desired output :
INSERT INTO random(userID, userNAME, chaID, chaNAME, goal, gender,row_number,dummy)
Select usr.userID,
usr.userNAME,
usr.chaID,
usr.chaNAME,
usr.goal,
usr.gender,
usr.row_num-usr_grp.min_row_num+1 as row_number,
usr.userID as dummy
from temp_users_1 usr
inner join (
Select userID,
min(row_num) as min_row_num
from temp_users_2 group by userID
) usr_grp on usr.UserID=usr_grp.userID
where usr.row_num-usr_grp.min_row_num+1 <=3; -- Condition to show only 3 records of each users.
END$$
DELIMITER ;
Updates:
1- Added Event Creation.
2- Assuming you are inserting repetitive user records into table name random.
3- This Event will execute daily at 12:00 AM.
Note:
1- You may have to change the table names if tables names are different as in answer.
2- Make sure that you have enabled MySQL Event scheduler in Configuration file otherwise event will not run automatically.
Here is the link which help you enabling MySQL event scheduler if not enabled:
http://geeksterminal.com/enable-mysql-event-scheduler-status/1711/

MySQL - Recursive Reorder Algorithm / UPDATE with Variable Incrementation

Sorry for the kind of meaningless title, but I couldn't come up with a more fitting one.
I have a MySQL table, which looks like this:
SELECT * FROM `table`
+----+-----------+----------+-------+
| id | dimension | order_by | value |
+----+-----------+----------+-------+
| 1 | 1 | 1 | 1st |
| 2 | 1 | 100 | 3rd |
| 3 | 2 | 300 | 5th |
| 4 | 3 | 999 | 6th |
| 5 | 1 | 2 | 2nd |
| 6 | 2 | 1 | 4th |
+----+-----------+----------+-------+
I am listing all entries ordered by dimension (first) and order_by (second), which looks like this:
SELECT * FROM `table` ORDER BY `dimension`, `order_by`
+----+-----------+----------+-------+
| id | dimension | order_by | value |
+----+-----------+----------+-------+
| 1 | 1 | 1 | 1st |
| 5 | 1 | 2 | 2nd |
| 2 | 1 | 100 | 3rd |
| 6 | 2 | 1 | 4th |
| 3 | 2 | 300 | 5th |
| 4 | 3 | 999 | 6th |
+----+-----------+----------+-------+
Now I'd like to write a function, that rearranges the order_by, if possible with just one update query, to make it look that way:
SELECT * FROM `table` ORDER BY `dimension`, `order_by`
+----+-----------+----------+-------+
| id | dimension | order_by | value |
+----+-----------+----------+-------+
| 1 | 1 | 1 | 1st |
| 5 | 1 | 2 | 2nd |
| 2 | 1 | 3 | 3rd |
| 6 | 2 | 1 | 4th |
| 3 | 2 | 2 | 5th |
| 4 | 3 | 1 | 6th |
+----+-----------+----------+-------+
What I got so far (which, unfortunately, doesn't start recounting for each dimension):
UPDATE `table` AS `l`
JOIN (SELECT #i=1 FROM `table`) AS `i`
SET `order_by` = #i:=i
Now, my question would be: Is it possible to do it with just one UPDATE query?
You have to introduce another variable holding the value of the previous row.
UPDATE Table1 t
INNER JOIN (
SELECT
id, /*your primary key I assume*/
#new_ob:=if(#prev != dimension, 1, #new_ob + 1) as new_ob,
#prev := dimension /*In this line, the value of the current row is assigned. In the previous line, the variable still holds the value of the previous row*/
FROM
Table1
, (SELECT #prev := null, #new_ob := 0) var_init_subquery
ORDER BY dimension, order_by
) st ON t.id = st.id
SET t.order_by = st.new_ob;
see it working live in an sqlfiddle

SQL, difficult fetching data query

Suppose I have such a table:
+-----+---------+-------+
| ID | TIME | DAY |
+-----+---------+-------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 3 | 1 |
| 1 | 1 | 2 |
| 2 | 2 | 2 |
| 3 | 3 | 2 |
| 1 | 1 | 3 |
| 2 | 2 | 3 |
| 3 | 3 | 3 |
| 1 | 1 | 4 |
| 2 | 2 | 4 |
| 3 | 3 | 4 |
| 1 | 1 | 5 |
| 2 | 2 | 5 |
| 3 | 3 | 5 |
+-----+---------+-------+
I want to fetch a table which represents 2 IDs which got the largest sum of TIME within the last 3 days (means from 3 to 5 in a DAY column)
So the correct result would be:
+-----+---------+
| ID | SUM |
+-----+---------+
| 3 | 9 |
| 2 | 6 |
+-----+---------+
The original table is much larger and more complex. So i need a generic approach.
Thanks in advance.
And so I just learned that MySQL used LIMIT instead of TOP...
fiddle
CREATE TABLE tbl (ID INT,tm INT,dy INT);
INSERT INTO tbl (id, tm, dy) VALUES
(1,1,1)
,(2,2,1)
,(3,3,1)
,(1,1,2)
,(1,1,1)
SELECT ID
,SUM(SumTimeForDay) SumTimeFromLastThreeDays
FROM (SELECT ID
,SUM(tm) SumTimeForDay
FROM tbl
GROUP BY ID, dy
HAVING dy > MAX(dy) -3) a
GROUP BY id
ORDER BY SUM(SumTimeForDay) DESC
LIMIT 2
select t1.`id`, sum(t1.`time`) as `sum`
from `table` t1
inner join ( select distinct `day` from `table` order by `day` desc limit 3 ) t2
on t2.`da`y = t1.`day`
group by t1.`id`
order by sum(t1.`time`) desc
limit 2

Sum up values from rows in MySQL table

I have added a new column 'sums' to my table and I am trying to sum up values from 'vals' column then update 'sums' in the same table, according to the algorithm shown below in the table.
I could write a few loops in PHP but I don't think it would be nice.
Any clue how to write it nicely?
--------------------------------------------------
| id | sets | parts | vals | sums |
|-------|---------|---------|----------|---------|
| 1 | 1 | 1 | 2 | 2 |
|-------|---------|---------|----------|---------|
| 2 | 1 | 2 | 3 | 2+3=5 |
|-------|---------|---------|----------|---------|
| 3 | 1 | 3 | 5 |2+3+5=10 |
|-------|---------|---------|----------|---------|
| 4 | 2 | 1 | 4 | 4 |
|-------|---------|---------|----------|---------|
| 5 | 2 | 2 | 1 | 4+1=5 |
|-------|---------|---------|----------|---------|
| 6 | 2 | 3 | 2 | 4+1+2=7 |
|-------|---------|---------|----------|---------|
| 7 | 3 | 1 | 6 | 6 |
|-------|---------|---------|----------|---------|
This should return the value you want for sums:
SELECT t.id
, IF(t.sets=#prev_sets,#i:=#i+t.vals,#i:=t.vals) AS `sums`
, #prev_sets := t.sets AS prev_sets
FROM mytable t
JOIN (SELECT #prev_sets := NULL, #i := 0 ) i
ORDER BY t.sets, t.parts
You can use this as an inline view in an update statement
UPDATE ( SELECT t.id
, IF(t.sets=#prev_sets,#i:=#i+t.vals,#i:=t.vals) AS `sums`
, #prev_sets := t.sets AS prev_sets
FROM mytable t
JOIN (SELECT #prev_sets := NULL, #i := 0 ) i
ORDER BY t.sets, t.parts
) s
JOIN mytable r
ON r.id = s.id
SET r.sums = s.sums
From the example data, it looks like you want the "groupings" on sets, and you want to order on parts within each group.