I have two tables, sort table and assign table
SortID | Name |
---|---|
0 | A |
1 | B |
2 | C |
3 | D |
I want assign mission to everyone, start with a special sortID example: start with sortID 2, and change order next week. result as below:
Date | Week | MissionA | MissionB | MissionC | MissionD |
---|---|---|---|---|---|
2021/1/3 | 1 | C | D | A | B |
2021/1/4 | 1 | C | D | A | B |
2021/1/5 | 1 | C | D | A | B |
2021/1/6 | 1 | C | D | A | B |
2021/1/7 | 1 | C | D | A | B |
2021/1/8 | 1 | C | D | A | B |
2021/1/9 | 1 | C | D | A | B |
2021/1/10 | 2 | D | A | B | C |
2021/1/11 | 2 | D | A | B | C |
Advertisement
Answer
If you do not know the number of rows in the sorts
table then you can generate the values as rows (instead of columns):
SELECT d.dt,
d.week,
MOD(d.week + s.sortid, s.num_sorts) AS mission,
s.name
FROM (
SELECT DATE '2021-01-02' + LEVEL AS dt,
CEIL(LEVEL / 7) AS week
FROM DUAL
CONNECT BY LEVEL <= 9
) d
CROSS JOIN (
SELECT sortid,
name,
COUNT(*) OVER() AS num_sorts
FROM sorts
) s
Which, for the sample data:
CREATE TABLE sorts (SortID, Name) AS
SELECT 0, 'A' FROM DUAL UNION ALL
SELECT 1, 'B' FROM DUAL UNION ALL
SELECT 2, 'C' FROM DUAL UNION ALL
SELECT 3, 'D' FROM DUAL;
Outputs:
DT WEEK MISSION NAME 03-JAN-21 1 1 A 03-JAN-21 1 2 B 03-JAN-21 1 3 C 03-JAN-21 1 0 D 04-JAN-21 1 1 A 04-JAN-21 1 2 B 04-JAN-21 1 3 C 04-JAN-21 1 0 D 05-JAN-21 1 1 A 05-JAN-21 1 2 B 05-JAN-21 1 3 C 05-JAN-21 1 0 D 06-JAN-21 1 1 A 06-JAN-21 1 2 B 06-JAN-21 1 3 C 06-JAN-21 1 0 D 07-JAN-21 1 1 A 07-JAN-21 1 2 B 07-JAN-21 1 3 C 07-JAN-21 1 0 D 08-JAN-21 1 1 A 08-JAN-21 1 2 B 08-JAN-21 1 3 C 08-JAN-21 1 0 D 09-JAN-21 1 1 A 09-JAN-21 1 2 B 09-JAN-21 1 3 C 09-JAN-21 1 0 D 10-JAN-21 2 2 A 10-JAN-21 2 3 B 10-JAN-21 2 0 C 10-JAN-21 2 1 D 11-JAN-21 2 2 A 11-JAN-21 2 3 B 11-JAN-21 2 0 C 11-JAN-21 2 1 D
Note: If you do not know how many columns there will be in the output, it is very difficult to PIVOT
the columns to rows as SQL (not just Oracle) does not support dynamic pivoting. Pivoting dynamic data to columns would, typically, be something that is done in the middle tier (PHP, Java, C#, Python, etc.) application.
If you know the number of rows in the sorts
table then you can use conditional aggregation to pivot the columns to rows:
SELECT d.dt,
d.week,
MAX(
CASE MOD(4 + MOD(3 + s.sortid - d.week, 4), 4)
WHEN 0
THEN s.name
END
) AS missionA,
MAX(
CASE MOD(4 + MOD(3 + s.sortid - d.week, 4), 4)
WHEN 1
THEN s.name
END
) AS missionB,
MAX(
CASE MOD(4 + MOD(3 + s.sortid - d.week, 4), 4)
WHEN 2
THEN s.name
END
) AS missionC,
MAX(
CASE MOD(4 + MOD(3 + s.sortid - d.week, 4), 4)
WHEN 3
THEN s.name
END
) AS missionD
FROM (
SELECT DATE '2021-01-02' + LEVEL AS dt,
CEIL(LEVEL / 7) AS week
FROM DUAL
CONNECT BY LEVEL <= 9
) d
CROSS JOIN sorts s
GROUP BY dt, week
ORDER BY dt
Which outputs:
DT WEEK MISSIONA MISSIONB MISSIONC MISSIOND 03-JAN-21 1 C D A B 04-JAN-21 1 C D A B 05-JAN-21 1 C D A B 06-JAN-21 1 C D A B 07-JAN-21 1 C D A B 08-JAN-21 1 C D A B 09-JAN-21 1 C D A B 10-JAN-21 2 D A B C 11-JAN-21 2 D A B C
db<>fiddle here