首页 > 解决方案 > 使用特殊排序号排序

问题描述

我有两个表,排序表和分配表

排序ID 姓名
0 一种
1
2 C
3 D

我想给每个人分配任务,从一个特殊的 sortID 示例开始:从 sortID 2 开始,下周更改顺序。结果如下:

日期 星期 使命A 任务B 使命C 使命D
2021/1/3 1 C D 一种
2021/1/4 1 C D 一种
2021/1/5 1 C D 一种
2021/1/6 1 C D 一种
2021/1/7 1 C D 一种
2021/1/8 1 C D 一种
2021/1/9 1 C D 一种
2021/1/10 2 D 一种 C
2021/1/11 2 D 一种 C

标签: sqloracle

解决方案


如果您不知道sorts表中的行数,则可以将值生成为行(而不是列):

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

其中,对于样本数据:

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;

输出:

DT 星期 使命 姓名
21 年 1 月 3 日 1 1 一种
21 年 1 月 3 日 1 2
21 年 1 月 3 日 1 3 C
21 年 1 月 3 日 1 0 D
21 年 1 月 4 日 1 1 一种
21 年 1 月 4 日 1 2
21 年 1 月 4 日 1 3 C
21 年 1 月 4 日 1 0 D
21 年 1 月 5 日 1 1 一种
21 年 1 月 5 日 1 2
21 年 1 月 5 日 1 3 C
21 年 1 月 5 日 1 0 D
21 年 1 月 6 日 1 1 一种
21 年 1 月 6 日 1 2
21 年 1 月 6 日 1 3 C
21 年 1 月 6 日 1 0 D
21 年 1 月 7 日 1 1 一种
21 年 1 月 7 日 1 2
21 年 1 月 7 日 1 3 C
21 年 1 月 7 日 1 0 D
21 年 1 月 8 日 1 1 一种
21 年 1 月 8 日 1 2
21 年 1 月 8 日 1 3 C
21 年 1 月 8 日 1 0 D
21 年 1 月 9 日 1 1 一种
21 年 1 月 9 日 1 2
21 年 1 月 9 日 1 3 C
21 年 1 月 9 日 1 0 D
21 年 1 月 10 日 2 2 一种
21 年 1 月 10 日 2 3
21 年 1 月 10 日 2 0 C
21 年 1 月 10 日 2 1 D
21 年 1 月 11 日 2 2 一种
21 年 1 月 11 日 2 3
21 年 1 月 11 日 2 0 C
21 年 1 月 11 日 2 1 D

注意:如果您不知道输出中会有多少列,则很难PIVOT将列转换为行,因为 SQL(不仅仅是 Oracle)不支持动态透视。将动态数据透视到列通常是在中间层(PHP、Java、C#、Python 等)应用程序中完成的。


如果您知道表中的行数,sorts则可以使用条件聚合将列转为行:

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

哪个输出:

DT 星期 使命 使命B 使命 使命
21 年 1 月 3 日 1 C D 一种
21 年 1 月 4 日 1 C D 一种
21 年 1 月 5 日 1 C D 一种
21 年 1 月 6 日 1 C D 一种
21 年 1 月 7 日 1 C D 一种
21 年 1 月 8 日 1 C D 一种
21 年 1 月 9 日 1 C D 一种
21 年 1 月 10 日 2 D 一种 C
21 年 1 月 11 日 2 D 一种 C

db<>在这里摆弄


推荐阅读