Oracle SQL: CONNECT BY LEVEL 返回许多行
Oracle SQL: CONNECT BY LEVEL returning many rows
我第一次使用 CONNECT BY 命令,我了解它可能会用它创建循环。我试图创建一个查询,为开始时间和结束时间之间的每个时间戳生成一行,间隔可变。当我 运行 这个查询分别针对每个 'route' 时,它工作得很好。但是当我尝试同时为两条路线 运行 时,循环继续进行。
我做错了什么?
SELECT ROUTE_NAME, START_TIME + (LEVEL - 1) * TIME_PERIOD OUTPUT_MOMENT
FROM (SELECT *
FROM (SELECT 1 / 24 AS TIME_PERIOD,
SYSDATE - 8 / 24 AS START_TIME,
SYSDATE + 3 / 24 AS END_TIME,
'ROUTE A' ROUTE_NAME
FROM DUAL
UNION ALL
SELECT 1 / 48 AS TIME_PERIOD,
SYSDATE - 8 / 24 AS START_TIME,
SYSDATE + 3 / 24 AS END_TIME,
'ROUTE B' ROUTE_NAME
FROM DUAL)
WHERE ROUTE_NAME IN ('ROUTE A')
--WHERE ROUTE_NAME IN ('ROUTE B')
--WHERE ROUTE_NAME IN ('ROUTE A', 'ROUTE B')
)
CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / TIME_PERIOD
路线 A 的结果:
* ROUTE_NAME OUTPUT_MOMENT
* ROUTE A 9/3/2018 5:41:01
* ROUTE A 9/3/2018 6:41:01
* ROUTE A 9/3/2018 7:41:01
* ROUTE A 9/3/2018 8:41:01
* ROUTE A 9/3/2018 9:41:01
* ROUTE A 9/3/2018 10:41:01
* ROUTE A 9/3/2018 11:41:01
* ROUTE A 9/3/2018 12:41:01
* ROUTE A 9/3/2018 13:41:01
* ROUTE A 9/3/2018 14:41:01
* ROUTE A 9/3/2018 15:41:01
路线 B 的结果:
* ROUTE_NAME OUTPUT_MOMENT
* ROUTE B 9/3/2018 5:42:34
* ROUTE B 9/3/2018 6:12:34
* ROUTE B 9/3/2018 6:42:34
* ROUTE B 9/3/2018 7:12:34
* ROUTE B 9/3/2018 7:42:34
* ROUTE B 9/3/2018 8:12:34
* ROUTE B 9/3/2018 8:42:34
* ROUTE B 9/3/2018 9:12:34
* ROUTE B 9/3/2018 9:42:34
* ROUTE B 9/3/2018 10:12:34
* ROUTE B 9/3/2018 10:42:34
* ROUTE B 9/3/2018 11:12:34
* ROUTE B 9/3/2018 11:42:34
* ROUTE B 9/3/2018 12:12:34
* ROUTE B 9/3/2018 12:42:34
* ROUTE B 9/3/2018 13:12:34
* ROUTE B 9/3/2018 13:42:34
* ROUTE B 9/3/2018 14:12:34
* ROUTE B 9/3/2018 14:42:34
* ROUTE B 9/3/2018 15:12:34
* ROUTE B 9/3/2018 15:42:34
* ROUTE B 9/3/2018 16:12:34
* ROUTE B 9/3/2018 16:42:34
两者的结果(存在更多行):
* ROUTE_NAME OUTPUT_MOMENT
* ROUTE A 9/3/2018 5:43:21
* ROUTE A 9/3/2018 6:43:21
* ROUTE A 9/3/2018 7:43:21
* ROUTE A 9/3/2018 8:43:21
* ROUTE A 9/3/2018 9:43:21
* ROUTE A 9/3/2018 10:43:21
* ROUTE A 9/3/2018 11:43:21
* ROUTE A 9/3/2018 12:43:21
* ROUTE A 9/3/2018 13:43:21
* ROUTE A 9/3/2018 14:43:21
* ROUTE A 9/3/2018 15:43:21
* ROUTE B 9/3/2018 11:13:21
* ROUTE B 9/3/2018 11:43:21
* ROUTE B 9/3/2018 12:13:21
* ROUTE B 9/3/2018 12:43:21
* ROUTE B 9/3/2018 13:13:21
* ROUTE B 9/3/2018 13:43:21
* ROUTE B 9/3/2018 14:13:21
* ROUTE B 9/3/2018 14:43:21
* ROUTE B 9/3/2018 15:13:21
* ROUTE B 9/3/2018 15:43:21
* ROUTE B 9/3/2018 16:13:21
* ROUTE B 9/3/2018 16:43:21
* ROUTE B 9/3/2018 10:43:21
* ROUTE B 9/3/2018 11:13:21
* ROUTE B 9/3/2018 11:43:21
* ROUTE B 9/3/2018 12:13:21
* ROUTE B 9/3/2018 12:43:21
* ROUTE B 9/3/2018 13:13:21
* ROUTE B 9/3/2018 13:43:21
* ROUTE B 9/3/2018 14:13:21
* ROUTE B 9/3/2018 14:43:21
* ROUTE B 9/3/2018 15:13:21
* ROUTE B 9/3/2018 15:43:21
* ROUTE B 9/3/2018 16:13:21
* ROUTE B 9/3/2018 16:43:21
* ROUTE B 9/3/2018 10:13:21
* ROUTE A 9/3/2018 15:43:21
* ROUTE B 9/3/2018 11:13:21
* ROUTE B 9/3/2018 11:43:21
* ROUTE B 9/3/2018 12:13:21
* ROUTE B 9/3/2018 12:43:21
* ROUTE B 9/3/2018 13:13:21
* ROUTE B 9/3/2018 13:43:21
* ROUTE B 9/3/2018 14:13:21
* ROUTE B 9/3/2018 14:43:21
* ROUTE B 9/3/2018 15:13:21
* ROUTE B 9/3/2018 15:43:21
* ROUTE B 9/3/2018 16:13:21
* ROUTE B 9/3/2018 16:43:21
* ROUTE B 9/3/2018 10:43:21
* ROUTE B 9/3/2018 11:13:21
* ROUTE B 9/3/2018 11:43:21
* ROUTE B 9/3/2018 12:13:21
* ROUTE B 9/3/2018 12:43:21
* ROUTE B 9/3/2018 13:13:21
* ROUTE B 9/3/2018 13:43:21
* ROUTE B 9/3/2018 14:13:21
* ROUTE B 9/3/2018 14:43:21
* ROUTE B 9/3/2018 15:13:21
* ROUTE B 9/3/2018 15:43:21
* ROUTE B 9/3/2018 16:13:21
* ROUTE B 9/3/2018 16:43:21
* ROUTE B 9/3/2018 9:43:21
* ROUTE A 9/3/2018 14:43:21
* ROUTE A 9/3/2018 15:43:21
* ROUTE B 9/3/2018 11:13:21
* ROUTE B 9/3/2018 11:43:21
* ROUTE B 9/3/2018 12:13:21
* ROUTE B 9/3/2018 12:43:21
* ROUTE B 9/3/2018 13:13:21
* ROUTE B 9/3/2018 13:43:21
* ROUTE B 9/3/2018 14:13:21
* ROUTE B 9/3/2018 14:43:21
* ROUTE B 9/3/2018 15:13:21
* ROUTE B 9/3/2018 15:43:21
* ROUTE B 9/3/2018 16:13:21
* ROUTE B 9/3/2018 16:43:21
* ROUTE B 9/3/2018 10:43:21
* ROUTE B 9/3/2018 11:13:21
* ROUTE B 9/3/2018 11:43:21
* ROUTE B 9/3/2018 12:13:21
* ROUTE B 9/3/2018 12:43:21
connect by
仅基于时间,因此您每次都连接路线 A 和路线 B,反之亦然。
简单的解决方法似乎是:
CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / TIME_PERIOD
AND ROUTE_NAME = PRIOR ROUTE_NAME
一次限制为一条路线;但这会形成一个循环,因此您还需要添加一个 non-deterministc 函数调用以防止这种情况发生;例如:
CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / TIME_PERIOD
AND ROUTE_NAME = PRIOR ROUTE_NAME
AND PRIOR DBMS_RANDOM.VALUE() IS NOT NULL
得到:
ROUTE_NAME OUTPUT_MOMENT
---------- -------------------
ROUTE A 2018-03-09 05:00:08
ROUTE A 2018-03-09 06:00:08
ROUTE A 2018-03-09 07:00:08
ROUTE A 2018-03-09 08:00:08
ROUTE A 2018-03-09 09:00:08
ROUTE A 2018-03-09 10:00:08
ROUTE A 2018-03-09 11:00:08
ROUTE A 2018-03-09 12:00:08
ROUTE A 2018-03-09 13:00:08
ROUTE A 2018-03-09 14:00:08
ROUTE A 2018-03-09 15:00:08
ROUTE B 2018-03-09 05:00:08
ROUTE B 2018-03-09 05:30:08
ROUTE B 2018-03-09 06:00:08
ROUTE B 2018-03-09 06:30:08
ROUTE B 2018-03-09 07:00:08
ROUTE B 2018-03-09 07:30:08
ROUTE B 2018-03-09 08:00:08
ROUTE B 2018-03-09 08:30:08
ROUTE B 2018-03-09 09:00:08
ROUTE B 2018-03-09 09:30:08
ROUTE B 2018-03-09 10:00:08
ROUTE B 2018-03-09 10:30:08
ROUTE B 2018-03-09 11:00:08
ROUTE B 2018-03-09 11:30:08
ROUTE B 2018-03-09 12:00:08
ROUTE B 2018-03-09 12:30:08
ROUTE B 2018-03-09 13:00:08
ROUTE B 2018-03-09 13:30:08
ROUTE B 2018-03-09 14:00:08
ROUTE B 2018-03-09 14:30:08
ROUTE B 2018-03-09 15:00:08
ROUTE B 2018-03-09 15:30:08
ROUTE B 2018-03-09 16:00:08
34 rows selected.
您还可以执行两个 connect by
查询并将结果合并在一起,可能会将时间范围拉入 CTE 以避免重复:
WITH START_END AS (
SELECT SYSDATE - 8 / 24 AS START_TIME,
SYSDATE + 3 / 24 AS END_TIME
FROM DUAL
)
SELECT 'ROUTE A' ROUTE_NAME,
START_TIME + (LEVEL - 1) / 24 AS OUTPUT_MOMENT
FROM START_END
CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / (1 / 24)
UNION ALL
SELECT 'ROUTE B' ROUTE_NAME,
START_TIME + (LEVEL - 1) / 48 AS OUTPUT_MOMENT
FROM START_END
CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / (1 / 48)
使用 / ( 1 / 24)
看起来很奇怪,而您可以使用 * 24
,但实际上由于舍入误差,您得到的结果略有不同;对于后者,您会为路线 A 获得额外的一行。您可以进一步重新安排逻辑以避免混淆。
您在这里得到的是将分层查询的每个级别的行加倍。
考虑一个简单的例子:
WITH dbl AS (
SELECT * FROM dual UNION ALL SELECT *FROM dual
)
SELECT *FROM dbl CONNECT BY LEVEL <= N
对于N=2
查询returns 6行,对于N=6
它returns 126行,对于N=10
-- 2046行。
所以我们看到行数呈指数增长。
您的查询以类似的方式工作。
要解决此问题,您可以将 union all
移动到外部级别,运行 为每个路由单独的分层查询:
SELECT ROUTE_NAME, START_TIME + (lvl - 1) * TIME_PERIOD
FROM (
SELECT LEVEL AS lvl, ROUTE_NAME AS "ROUTE A"...
...
FROM DUAL CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / TIME_PERIOD
)
UNION ALL
SELECT ROUTE_NAME, START_TIME + (lvl - 1) * TIME_PERIOD
FROM (
SELECT LEVEL AS lvl, ROUTE_NAME AS "ROUTE B", ...
...
FROM DUAL CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / TIME_PERIOD
)
或使用 ROUTE_NAME = PRIOR ROUTE_NAME
阻止一条路线跟随另一条路线,正如另一个答案中所建议的那样。
我第一次使用 CONNECT BY 命令,我了解它可能会用它创建循环。我试图创建一个查询,为开始时间和结束时间之间的每个时间戳生成一行,间隔可变。当我 运行 这个查询分别针对每个 'route' 时,它工作得很好。但是当我尝试同时为两条路线 运行 时,循环继续进行。
我做错了什么?
SELECT ROUTE_NAME, START_TIME + (LEVEL - 1) * TIME_PERIOD OUTPUT_MOMENT
FROM (SELECT *
FROM (SELECT 1 / 24 AS TIME_PERIOD,
SYSDATE - 8 / 24 AS START_TIME,
SYSDATE + 3 / 24 AS END_TIME,
'ROUTE A' ROUTE_NAME
FROM DUAL
UNION ALL
SELECT 1 / 48 AS TIME_PERIOD,
SYSDATE - 8 / 24 AS START_TIME,
SYSDATE + 3 / 24 AS END_TIME,
'ROUTE B' ROUTE_NAME
FROM DUAL)
WHERE ROUTE_NAME IN ('ROUTE A')
--WHERE ROUTE_NAME IN ('ROUTE B')
--WHERE ROUTE_NAME IN ('ROUTE A', 'ROUTE B')
)
CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / TIME_PERIOD
路线 A 的结果:
* ROUTE_NAME OUTPUT_MOMENT
* ROUTE A 9/3/2018 5:41:01
* ROUTE A 9/3/2018 6:41:01
* ROUTE A 9/3/2018 7:41:01
* ROUTE A 9/3/2018 8:41:01
* ROUTE A 9/3/2018 9:41:01
* ROUTE A 9/3/2018 10:41:01
* ROUTE A 9/3/2018 11:41:01
* ROUTE A 9/3/2018 12:41:01
* ROUTE A 9/3/2018 13:41:01
* ROUTE A 9/3/2018 14:41:01
* ROUTE A 9/3/2018 15:41:01
路线 B 的结果:
* ROUTE_NAME OUTPUT_MOMENT
* ROUTE B 9/3/2018 5:42:34
* ROUTE B 9/3/2018 6:12:34
* ROUTE B 9/3/2018 6:42:34
* ROUTE B 9/3/2018 7:12:34
* ROUTE B 9/3/2018 7:42:34
* ROUTE B 9/3/2018 8:12:34
* ROUTE B 9/3/2018 8:42:34
* ROUTE B 9/3/2018 9:12:34
* ROUTE B 9/3/2018 9:42:34
* ROUTE B 9/3/2018 10:12:34
* ROUTE B 9/3/2018 10:42:34
* ROUTE B 9/3/2018 11:12:34
* ROUTE B 9/3/2018 11:42:34
* ROUTE B 9/3/2018 12:12:34
* ROUTE B 9/3/2018 12:42:34
* ROUTE B 9/3/2018 13:12:34
* ROUTE B 9/3/2018 13:42:34
* ROUTE B 9/3/2018 14:12:34
* ROUTE B 9/3/2018 14:42:34
* ROUTE B 9/3/2018 15:12:34
* ROUTE B 9/3/2018 15:42:34
* ROUTE B 9/3/2018 16:12:34
* ROUTE B 9/3/2018 16:42:34
两者的结果(存在更多行):
* ROUTE_NAME OUTPUT_MOMENT
* ROUTE A 9/3/2018 5:43:21
* ROUTE A 9/3/2018 6:43:21
* ROUTE A 9/3/2018 7:43:21
* ROUTE A 9/3/2018 8:43:21
* ROUTE A 9/3/2018 9:43:21
* ROUTE A 9/3/2018 10:43:21
* ROUTE A 9/3/2018 11:43:21
* ROUTE A 9/3/2018 12:43:21
* ROUTE A 9/3/2018 13:43:21
* ROUTE A 9/3/2018 14:43:21
* ROUTE A 9/3/2018 15:43:21
* ROUTE B 9/3/2018 11:13:21
* ROUTE B 9/3/2018 11:43:21
* ROUTE B 9/3/2018 12:13:21
* ROUTE B 9/3/2018 12:43:21
* ROUTE B 9/3/2018 13:13:21
* ROUTE B 9/3/2018 13:43:21
* ROUTE B 9/3/2018 14:13:21
* ROUTE B 9/3/2018 14:43:21
* ROUTE B 9/3/2018 15:13:21
* ROUTE B 9/3/2018 15:43:21
* ROUTE B 9/3/2018 16:13:21
* ROUTE B 9/3/2018 16:43:21
* ROUTE B 9/3/2018 10:43:21
* ROUTE B 9/3/2018 11:13:21
* ROUTE B 9/3/2018 11:43:21
* ROUTE B 9/3/2018 12:13:21
* ROUTE B 9/3/2018 12:43:21
* ROUTE B 9/3/2018 13:13:21
* ROUTE B 9/3/2018 13:43:21
* ROUTE B 9/3/2018 14:13:21
* ROUTE B 9/3/2018 14:43:21
* ROUTE B 9/3/2018 15:13:21
* ROUTE B 9/3/2018 15:43:21
* ROUTE B 9/3/2018 16:13:21
* ROUTE B 9/3/2018 16:43:21
* ROUTE B 9/3/2018 10:13:21
* ROUTE A 9/3/2018 15:43:21
* ROUTE B 9/3/2018 11:13:21
* ROUTE B 9/3/2018 11:43:21
* ROUTE B 9/3/2018 12:13:21
* ROUTE B 9/3/2018 12:43:21
* ROUTE B 9/3/2018 13:13:21
* ROUTE B 9/3/2018 13:43:21
* ROUTE B 9/3/2018 14:13:21
* ROUTE B 9/3/2018 14:43:21
* ROUTE B 9/3/2018 15:13:21
* ROUTE B 9/3/2018 15:43:21
* ROUTE B 9/3/2018 16:13:21
* ROUTE B 9/3/2018 16:43:21
* ROUTE B 9/3/2018 10:43:21
* ROUTE B 9/3/2018 11:13:21
* ROUTE B 9/3/2018 11:43:21
* ROUTE B 9/3/2018 12:13:21
* ROUTE B 9/3/2018 12:43:21
* ROUTE B 9/3/2018 13:13:21
* ROUTE B 9/3/2018 13:43:21
* ROUTE B 9/3/2018 14:13:21
* ROUTE B 9/3/2018 14:43:21
* ROUTE B 9/3/2018 15:13:21
* ROUTE B 9/3/2018 15:43:21
* ROUTE B 9/3/2018 16:13:21
* ROUTE B 9/3/2018 16:43:21
* ROUTE B 9/3/2018 9:43:21
* ROUTE A 9/3/2018 14:43:21
* ROUTE A 9/3/2018 15:43:21
* ROUTE B 9/3/2018 11:13:21
* ROUTE B 9/3/2018 11:43:21
* ROUTE B 9/3/2018 12:13:21
* ROUTE B 9/3/2018 12:43:21
* ROUTE B 9/3/2018 13:13:21
* ROUTE B 9/3/2018 13:43:21
* ROUTE B 9/3/2018 14:13:21
* ROUTE B 9/3/2018 14:43:21
* ROUTE B 9/3/2018 15:13:21
* ROUTE B 9/3/2018 15:43:21
* ROUTE B 9/3/2018 16:13:21
* ROUTE B 9/3/2018 16:43:21
* ROUTE B 9/3/2018 10:43:21
* ROUTE B 9/3/2018 11:13:21
* ROUTE B 9/3/2018 11:43:21
* ROUTE B 9/3/2018 12:13:21
* ROUTE B 9/3/2018 12:43:21
connect by
仅基于时间,因此您每次都连接路线 A 和路线 B,反之亦然。
简单的解决方法似乎是:
CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / TIME_PERIOD
AND ROUTE_NAME = PRIOR ROUTE_NAME
一次限制为一条路线;但这会形成一个循环,因此您还需要添加一个 non-deterministc 函数调用以防止这种情况发生;例如:
CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / TIME_PERIOD
AND ROUTE_NAME = PRIOR ROUTE_NAME
AND PRIOR DBMS_RANDOM.VALUE() IS NOT NULL
得到:
ROUTE_NAME OUTPUT_MOMENT
---------- -------------------
ROUTE A 2018-03-09 05:00:08
ROUTE A 2018-03-09 06:00:08
ROUTE A 2018-03-09 07:00:08
ROUTE A 2018-03-09 08:00:08
ROUTE A 2018-03-09 09:00:08
ROUTE A 2018-03-09 10:00:08
ROUTE A 2018-03-09 11:00:08
ROUTE A 2018-03-09 12:00:08
ROUTE A 2018-03-09 13:00:08
ROUTE A 2018-03-09 14:00:08
ROUTE A 2018-03-09 15:00:08
ROUTE B 2018-03-09 05:00:08
ROUTE B 2018-03-09 05:30:08
ROUTE B 2018-03-09 06:00:08
ROUTE B 2018-03-09 06:30:08
ROUTE B 2018-03-09 07:00:08
ROUTE B 2018-03-09 07:30:08
ROUTE B 2018-03-09 08:00:08
ROUTE B 2018-03-09 08:30:08
ROUTE B 2018-03-09 09:00:08
ROUTE B 2018-03-09 09:30:08
ROUTE B 2018-03-09 10:00:08
ROUTE B 2018-03-09 10:30:08
ROUTE B 2018-03-09 11:00:08
ROUTE B 2018-03-09 11:30:08
ROUTE B 2018-03-09 12:00:08
ROUTE B 2018-03-09 12:30:08
ROUTE B 2018-03-09 13:00:08
ROUTE B 2018-03-09 13:30:08
ROUTE B 2018-03-09 14:00:08
ROUTE B 2018-03-09 14:30:08
ROUTE B 2018-03-09 15:00:08
ROUTE B 2018-03-09 15:30:08
ROUTE B 2018-03-09 16:00:08
34 rows selected.
您还可以执行两个 connect by
查询并将结果合并在一起,可能会将时间范围拉入 CTE 以避免重复:
WITH START_END AS (
SELECT SYSDATE - 8 / 24 AS START_TIME,
SYSDATE + 3 / 24 AS END_TIME
FROM DUAL
)
SELECT 'ROUTE A' ROUTE_NAME,
START_TIME + (LEVEL - 1) / 24 AS OUTPUT_MOMENT
FROM START_END
CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / (1 / 24)
UNION ALL
SELECT 'ROUTE B' ROUTE_NAME,
START_TIME + (LEVEL - 1) / 48 AS OUTPUT_MOMENT
FROM START_END
CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / (1 / 48)
使用 / ( 1 / 24)
看起来很奇怪,而您可以使用 * 24
,但实际上由于舍入误差,您得到的结果略有不同;对于后者,您会为路线 A 获得额外的一行。您可以进一步重新安排逻辑以避免混淆。
您在这里得到的是将分层查询的每个级别的行加倍。
考虑一个简单的例子:
WITH dbl AS (
SELECT * FROM dual UNION ALL SELECT *FROM dual
)
SELECT *FROM dbl CONNECT BY LEVEL <= N
对于N=2
查询returns 6行,对于N=6
它returns 126行,对于N=10
-- 2046行。
所以我们看到行数呈指数增长。
您的查询以类似的方式工作。
要解决此问题,您可以将 union all
移动到外部级别,运行 为每个路由单独的分层查询:
SELECT ROUTE_NAME, START_TIME + (lvl - 1) * TIME_PERIOD
FROM (
SELECT LEVEL AS lvl, ROUTE_NAME AS "ROUTE A"...
...
FROM DUAL CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / TIME_PERIOD
)
UNION ALL
SELECT ROUTE_NAME, START_TIME + (lvl - 1) * TIME_PERIOD
FROM (
SELECT LEVEL AS lvl, ROUTE_NAME AS "ROUTE B", ...
...
FROM DUAL CONNECT BY (LEVEL - 1) <= (END_TIME - START_TIME) / TIME_PERIOD
)
或使用 ROUTE_NAME = PRIOR ROUTE_NAME
阻止一条路线跟随另一条路线,正如另一个答案中所建议的那样。