sql - 使用特殊排序号排序
问题描述
我有两个表,排序表和分配表
排序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 |
解决方案
如果您不知道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<>在这里摆弄
推荐阅读
- javascript - Libgdx HTML5 AnimationScheduler 长度为空
- python - Flask+Celery 作为守护进程
- excel - 在加载项中将宏添加到 Excel 功能区
- java - Maven 无法下载 geotools 依赖项
- r - 更改数据集时,在闪亮的应用程序中动态显示列名闪烁错误
- ruby-on-rails - 处理可能更改的 json 响应(并非每次都包含所有键,可以添加新键)
- c - 如何使用动态规划找到背包问题的最优解中的项目?
- java - 如何在 .deepToString 输出之间添加单独的行?
- android - 不允许明文 http 流量
- python - 以不同方式存储的文本数据