I have a table with values
ID(PK) MAIN_ID SUB_ID
1 2 2
2 2 3
5 1 1
3 1 3
9 1 4
8 1 5
4 4 2
7 4 3
11 4 4
10 4 6
6 4 7
12 4 8
I want to reorder them in such a way that MAIN_ID's will contain 1 , 2 , 3 , 4 and SUB_IDs will container 1 , 2 , 3 , 4 , 5 etc. Basically i want to remove the missing numbers and make the MAIN_ID and SUB_ID follow numerical order without missing numbers
Desired result as requested
ID(PK) MAIN_ID SUB_ID
1 2 1(Prev 2)
2 2 2(Prev 3)
5 1 1
3 1 2(Prev 3)
9 1 3(Prev 4)
8 1 4(Prev 5)
4 3(Prev 4) 1(Prev 2)
7 3(Prev 4) 2(Prev 3)
11 3(Prev 4) 3(Prev 4)
10 3(Prev 4) 4(Prev 6)
6 3(Prev 4) 5(Prev 7)
12 3(Prev 4) 6(Prev 8)
```
Do you need this:
UPDATE test
JOIN ( SELECT ID,
DENSE_RANK() OVER (ORDER BY MAIN_ID) dr,
ROW_NUMBER() OVER (PARTITION BY MAIN_ID ORDER BY SUB_ID, ID) rn
FROM test ) t USING (ID)
SET test.MAIN_ID = dr, test.SUB_ID = rn;
?
fiddle
Related
I came across this question in a round of interview. A table has the following column.
ID
1
2
3
4
5
6
7
8
9
11
12
13
14
15
16
17
18
19
20
22
23
24
26
The question is to create a new column that starts with '1' and increments on the next ID whenever there is a multiple of 5. So the expected output is
ID
Result
1
1
2
1
3
1
4
1
5
1
6
2
7
2
8
2
9
2
11
2
12
2
13
2
14
2
15
2
16
3
17
3
18
3
19
3
20
3
22
4
23
4
24
4
26
4
You can combine two window functions: LAG() and SUM(). For example:
select id,
1 + sum(case when lid % 5 = 0 then 1 else 0 end) over(order by id) as v
from (
select *, lag(id) over(order by id) as lid from t
) x
order by id
Result:
id v
-- -
1 1
2 1
3 1
4 1
5 1
6 2
7 2
8 2
9 2
11 2
12 2
13 2
14 2
15 2
16 3
17 3
18 3
19 3
20 3
22 4
23 4
24 4
26 4
See running example at DB Fiddle.
For MySQL 5+ you may use, for example
SELECT id, (#result := COALESCE( #result + !(id % 5), 1 )) - !(id % 5) result
FROM t
CROSS JOIN (SELECT #result := NULL) init_variable
ORDER BY id
For MySQL 8+ use
SELECT id, 1 + SUM(!(id % 5)) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) resuls
FROM t
You can do this without a subquery:
select t.*,
1 + sum( (id % 5) = 0 ) over (order by id) - (id % 5 = 0)
from t
order by id;
What is the logic here? Calculate the cumulative sum of "5"s up to this row. Then subtract out the value on this row, because the increment takes effect on the next row.
It is also tempting to write this using a window frame clause, but that ends up being a wee bit more complicated because the first value is NULL:
select t.*,
1 + coalesce(sum( (id % 5) = 0 ) over (order by id rows between unbounded preceding and 1 preceding), 0)
from t
order by id;
Here is a db<>fiddle.
I have a table of matches of a game in a tournement.
Here is the mysql table:
id
player1
player1_score
player1_rating
player2
player2_score
player2_rating
tourney_id
round
1
1
9
1.05
2
3
5.34
5
1
2
3
4
5.21
4
9
3.34
5
1
3
5
9
3.52
6
2
5.24
5
1
4
1
9
6.23
3
0
4.74
5
2
5
2
8
9.43
4
9
1.23
5
2
6
3
9
3.41
5
7
6.23
5
2
7
1
9
5.22
4
2
2.43
5
3
8
2
3
4.21
3
9
5.22
5
3
9
5
1
7.31
6
9
3.43
5
3
How can I get the average player ratings for each individual player in a particular tourney?
Please note, there's two columns with player ids (player1, player2)
Based on your requirements (Even though you do not give us your expected results), I assume your code should be like this:
SELECT (SELECT SUM(player1_rating) / COUNT(DISTINCT player1)
FROM your_table GROUP BY player1) as avg_player1,
(SELECT SUM(player2_rating) / COUNT(DISTINCT player2) FROM your_table
GROUP BY player2) as avg_player2
FROM your_table
I revised the query to:
SELECT player_id
, tourney_id
, avg_player_rating = SUM(player_rating) / SUM(cnt)
FROM (
SELECT player_id = player1
, tourney_id
, player_rating = SUM(player1_rating)
, cnt = COUNT(*)
FROM tournament
GROUP BY tourney_id, player1
UNION ALL
SELECT player_id = player2
, tourney_id
, player_rating = SUM(player2_rating)
, cnt = COUNT(*)
FROM tournament
GROUP BY tourney_id, player2
) AS a
GROUP BY player_id, tourney_id
and this will give the result:
player_id tourney_id avg_player_rating
---------- ---------- --------------------
1 5 4.1666
2 5 6.3266
3 5 4.6450
4 5 2.3333
5 5 5.6866
6 5 4.3350
I hope that this is the result that you are looking for.
I have a table in the following format
ID SOURCE_ID
1 1
2 1
3 1
4 2
5 3
6 3
7 4
8 4
9 4
10 4
11 4
12 1
13 1
14 3
15 3
16 3
17 3
18 2
19 2
I want to be able to select 5 records MAX for each unique source_id.
So I should end up having returned 5 rows for source_id = 1, 5 rows for souce_id = 2, and so on.
Any ideas? Thank you in advance.
E.g.:
SELECT id
, source_id
FROM
( SELECT id
, source_id
, CASE WHEN #prev = source_id THEN #i:=#i+1 ELSE #i:=1 END i
, #prev := source_id prev
FROM my_table
, (SELECT #prev:=null,#i:=0) vars
ORDER
BY source_id
, id
) x
WHERE i <=5
ORDER
BY id;
I have below customer table with max qty.
I need a unique user who has max qty order by its group id.
Input:
id, customer_id, customer_group_id qty
1 1 3 1
2 1 3 10
3 1 3 5
4 2 2 10
5 2 2 1
6 2 2 2
7 3 1 5
8 3 1 10
9 4 4 1
10 4 4 2
11 4 4 2
Output should be:
id, customer_id, customer_group_id, qty
11 4 4 2
10 4 4 2 - This should be not selected
2 1 3 10
4 2 2 10
8 3 1 10
Query:
SELECT * FROM customer
WHERE qty IN ( SELECT MAX(qty) FROM customer GROUP BY customer_id)
ORDER BY customer_group_id DESC;
I tried above query but seems not working.
My table is "Activity_table", which have 4 columns. How can I create a function, which SUM each Peroson 2 previous and current activities?
My Activity_table
ID PID AID Act
1 1 1 12
2 1 2 32
3 2 1 5
4 1 3 21
5 2 2 12
6 2 3 19
7 1 4 11
8 2 4 6
PID-PersonID; AID-ActivitieID; Act-Activitie Value
My target:
ID PID AID Act SUM
1 1 1 12 12
2 1 2 32 44
3 2 1 5 5
4 1 3 21 65
5 2 2 12 17
6 2 3 19 36
7 1 4 11 64
8 2 4 6 37
Sum1=12; Sum2=32+12; Sum3=5; Sum4=21+32+12; Sum5=12+5; Sum6=19+12+5; Sum7=11+21+32; Sum8=6+19+12; Thank you,
To use the two previous and the current row,
SELECT ID,PID,AID,Act,
(SELECT SUM(Act)
FROM Activity_table
WHERE ID <= a.ID
AND ID >= a.ID - 2
AND PID = a.PID)
FROM Activity_table a;
You are taking the SUM according to the PID right? Then the last two rows of your target should be modified as,
7 1 4 11 **76**
8 2 4 6 **42**
The most flexible query is for your requirement is,
SELECT ID,PID,AID,Act,
(SELECT SUM(Act)
FROM Activity_table
WHERE ID <= a.ID
AND PID = a.PID)
FROM Activity_table a;
Then if you need only the flow of SUM of a particular PID, you can change it like this,
SELECT ID,PID,AID,Act,
(SELECT SUM(Act)
FROM Activity_table
WHERE ID <= a.ID
AND PID = a.PID)
FROM Activity_table a
WHERE PID = 2;
Result:
ID PID AID Act SUM
3 2 1 5 5
5 2 2 12 17
6 2 3 19 36
8 2 4 6 42
Sorry for the previous wrong Answers (deleted).
This produces the correct answer based on your example:
SET #LastPID = 0, #Act1 = 0,#Act2 = 0,#Act3 = 0;
SELECT ID,PID,AID,Act,`SUM` FROM
(
SELECT ID,PID,AID,Act,#Act3 := IF(#LastPID != PID, 0,#Act2),#Act2 := IF(#LastPID != PID, 0,#Act1), #Act1 := Act, #Act1 + #Act2 + #Act3 `SUM`, #LastPID := PID
FROM Activity_table
ORDER BY PID,ID
) sm
ORDER BY ID
;