Oracle 子句嵌套
Oracle Nesting With Clauses
当一条记录满足特定条件时,我需要将它们拆分为 2,并且在拆分后很难将它们连接在一起。
我有这个 table:
对于一天的会议,我需要将它们分成 2 场会议,一场在上午,一场在下午。在此示例中,我需要将测试 2 分成上午和下午 2 个会话。
我用过这个语句,它对我很有用:
WITH DATA
AS
(SELECT
CASE
WHEN level=1 THEN 'AM'
WHEN LEVEL=2 THEN 'PM'
END "Session"
FROM dual CONNECT BY level<3)
SELECT "Meeting","From","EndTime","StartTime","Session"
FROM "TEST", DATA
WHERE ("StartTime" < 12 AND "StartTime">=8) AND ( "EndTime" > 12 AND "EndTime" <= 17)
但是,当我尝试合并最后半天的其他会议时,出现以下错误:
ORA-32034: unsupported use of WITH clause
32034. 00000 - "unsupported use of WITH clause"
*Cause: Inproper use of WITH clause because one of the following two reasons
1. nesting of WITH clause within WITH clause not supported yet
2. For a set query, WITH clause can't be specified for a branch.
3. WITH clause can't sepecified within parentheses.
*Action: correct query and retry
Error at Line: 56 Column: 1
这是我使用的 sql 语句:
SELECT *
FROM
(
SELECT "Meeting","From","EndTime","StartTime" ,
CASE
WHEN "StartTime" >= 8 AND "EndTime" <= 12 THEN 'AM'
WHEN "StartTime" >= 12 AND "EndTime" <= 17 THEN 'PM'
ELSE 'UNKNOWN'
END "Session"
FROM "TEST"
WHERE ("StartTime" >= 8 AND "EndTime" <= 12)
OR
("StartTime" >= 12 AND "EndTime" <= 17)
) HalfDay
UNION ALL
(
WITH DATA
AS
(SELECT
CASE
WHEN level=1 THEN 'AM'
WHEN LEVEL=2 THEN 'PM'
END "Session"
FROM dual CONNECT BY level<3)
SELECT "Meeting","From","EndTime","StartTime","Session"
FROM "TEST", DATA
WHERE ("StartTime" < 12 AND "StartTime">=8) AND ( "EndTime" > 12 AND "EndTime" <= 17)
) FullDay
我该如何解决这个问题?
请查看附件中创建 table 和相关数据的脚本。
CREATE TABLE "TEST"
( "Meeting" VARCHAR2(20 BYTE),
"From" DATE,
"StartTime" NUMBER,
"EndTime" NUMBER
) ;
Insert into TEST ("Meeting","From","StartTime","EndTime") values ('Test 1',to_date('06-JUL-15','DD-MON-RR'),12,17);
Insert into TEST ("Meeting","From","StartTime","EndTime") values ('Test 2',to_date('12-DEC-15','DD-MON-RR'),8,17);
我的目标是得到这个输出
连同这个合一视图
您并没有真正嵌套两个 with 子句,但您确实在联合中嵌套了一个。
with
子句声明一个或多个子查询,并为它们分配一个可以在查询中进一步使用的名称,如视图。
这也是您在这里可以做的。将整个 with
子句和它定义的内联视图移到顶部。之后是联合部分。稍微清理一下后,它看起来像这样:
WITH
DATA AS
(SELECT
CASE
WHEN level=1 THEN 'AM'
WHEN LEVEL=2 THEN 'PM'
END "Session"
FROM dual CONNECT BY level < 3)
SELECT "Meeting","From","EndTime","StartTime" ,
CASE
WHEN "StartTime" >= 8 AND "EndTime" <= 12 THEN 'AM'
WHEN "StartTime" >= 12 AND "EndTime" <= 17 THEN 'PM'
ELSE 'UNKNOWN'
END "Session"
FROM "TEST"
WHERE ("StartTime" >= 8 AND "EndTime" <= 12)
OR
("StartTime" >= 12 AND "EndTime" <= 17)
UNION ALL
SELECT "Meeting", "From", "EndTime", "StartTime", "Session"
FROM "TEST", DATA
WHERE
"StartTime" < 12 AND "StartTime" >= 8 AND
"EndTime" > 12 AND "EndTime" <= 17
没有WITH
的相同查询:
SELECT "Meeting","From","EndTime","StartTime" ,
CASE
WHEN "StartTime" >= 8 AND "EndTime" <= 12 THEN 'AM'
WHEN "StartTime" >= 12 AND "EndTime" <= 17 THEN 'PM'
ELSE 'UNKNOWN'
END "Session"
FROM "TEST"
WHERE ("StartTime" >= 8 AND "EndTime" <= 12)
OR
("StartTime" >= 12 AND "EndTime" <= 17)
UNION ALL
SELECT "Meeting", "From", "EndTime", "StartTime", "Session"
FROM
"TEST",
(SELECT
CASE
WHEN level=1 THEN 'AM'
WHEN LEVEL=2 THEN 'PM'
END "Session"
FROM dual CONNECT BY level < 3)
WHERE
"StartTime" < 12 AND "StartTime" >= 8 AND
"EndTime" > 12 AND "EndTime" <= 17
使用两个子查询(省略并集)的更紧凑的解决方案。
第一个用于映射 table,提供一对一连接或拆分为两条记录。
第二个子查询转换你的日期源添加 "Duration" 键,代表
树状案例:仅上午、仅下午或上午 + 下午
剩下的就是一个简单的连接。
with join_helper as (
select 'AM' "Duration", 'AM' "Session" from dual union all
select 'PM' "Duration", 'PM' "Session" from dual union all
select 'AM-PM' "Duration", 'AM' "Session" from dual union all
select 'AM-PM' "Duration", 'PM' "Session" from dual),
session_duration as (
select test.*,
CASE
WHEN "StartTime" < 12 AND "EndTime" >= 12 THEN 'AM-PM'
WHEN "StartTime" < 12 THEN 'AM'
WHEN "EndTime" >= 12 THEN 'PM'
END "Duration"
from test)
select a."Meeting", a."From",a."StartTime",a."EndTime", b."Session"
from session_duration a, join_helper b
where a."Duration" = b."Duration"
;
您可能会发现查询中的逻辑不那么分散..
SELECT "Meeting","From","EndTime","StartTime" ,
CASE
WHEN "StartTime" >= 8 THEN 'AM'
END "Session"
FROM "TEST"
union all
SELECT "Meeting","From","EndTime","StartTime" ,
CASE
WHEN "EndTime" <= 17 THEN 'PM'
END "Session"
FROM "TEST"
where "StartTime" <12 AND "EndTime" <= 17 ;
当一条记录满足特定条件时,我需要将它们拆分为 2,并且在拆分后很难将它们连接在一起。 我有这个 table:
对于一天的会议,我需要将它们分成 2 场会议,一场在上午,一场在下午。在此示例中,我需要将测试 2 分成上午和下午 2 个会话。
我用过这个语句,它对我很有用:
WITH DATA
AS
(SELECT
CASE
WHEN level=1 THEN 'AM'
WHEN LEVEL=2 THEN 'PM'
END "Session"
FROM dual CONNECT BY level<3)
SELECT "Meeting","From","EndTime","StartTime","Session"
FROM "TEST", DATA
WHERE ("StartTime" < 12 AND "StartTime">=8) AND ( "EndTime" > 12 AND "EndTime" <= 17)
但是,当我尝试合并最后半天的其他会议时,出现以下错误:
ORA-32034: unsupported use of WITH clause
32034. 00000 - "unsupported use of WITH clause"
*Cause: Inproper use of WITH clause because one of the following two reasons
1. nesting of WITH clause within WITH clause not supported yet
2. For a set query, WITH clause can't be specified for a branch.
3. WITH clause can't sepecified within parentheses.
*Action: correct query and retry
Error at Line: 56 Column: 1
这是我使用的 sql 语句:
SELECT *
FROM
(
SELECT "Meeting","From","EndTime","StartTime" ,
CASE
WHEN "StartTime" >= 8 AND "EndTime" <= 12 THEN 'AM'
WHEN "StartTime" >= 12 AND "EndTime" <= 17 THEN 'PM'
ELSE 'UNKNOWN'
END "Session"
FROM "TEST"
WHERE ("StartTime" >= 8 AND "EndTime" <= 12)
OR
("StartTime" >= 12 AND "EndTime" <= 17)
) HalfDay
UNION ALL
(
WITH DATA
AS
(SELECT
CASE
WHEN level=1 THEN 'AM'
WHEN LEVEL=2 THEN 'PM'
END "Session"
FROM dual CONNECT BY level<3)
SELECT "Meeting","From","EndTime","StartTime","Session"
FROM "TEST", DATA
WHERE ("StartTime" < 12 AND "StartTime">=8) AND ( "EndTime" > 12 AND "EndTime" <= 17)
) FullDay
我该如何解决这个问题? 请查看附件中创建 table 和相关数据的脚本。
CREATE TABLE "TEST"
( "Meeting" VARCHAR2(20 BYTE),
"From" DATE,
"StartTime" NUMBER,
"EndTime" NUMBER
) ;
Insert into TEST ("Meeting","From","StartTime","EndTime") values ('Test 1',to_date('06-JUL-15','DD-MON-RR'),12,17);
Insert into TEST ("Meeting","From","StartTime","EndTime") values ('Test 2',to_date('12-DEC-15','DD-MON-RR'),8,17);
我的目标是得到这个输出
连同这个合一视图
您并没有真正嵌套两个 with 子句,但您确实在联合中嵌套了一个。
with
子句声明一个或多个子查询,并为它们分配一个可以在查询中进一步使用的名称,如视图。
这也是您在这里可以做的。将整个 with
子句和它定义的内联视图移到顶部。之后是联合部分。稍微清理一下后,它看起来像这样:
WITH
DATA AS
(SELECT
CASE
WHEN level=1 THEN 'AM'
WHEN LEVEL=2 THEN 'PM'
END "Session"
FROM dual CONNECT BY level < 3)
SELECT "Meeting","From","EndTime","StartTime" ,
CASE
WHEN "StartTime" >= 8 AND "EndTime" <= 12 THEN 'AM'
WHEN "StartTime" >= 12 AND "EndTime" <= 17 THEN 'PM'
ELSE 'UNKNOWN'
END "Session"
FROM "TEST"
WHERE ("StartTime" >= 8 AND "EndTime" <= 12)
OR
("StartTime" >= 12 AND "EndTime" <= 17)
UNION ALL
SELECT "Meeting", "From", "EndTime", "StartTime", "Session"
FROM "TEST", DATA
WHERE
"StartTime" < 12 AND "StartTime" >= 8 AND
"EndTime" > 12 AND "EndTime" <= 17
没有WITH
的相同查询:
SELECT "Meeting","From","EndTime","StartTime" ,
CASE
WHEN "StartTime" >= 8 AND "EndTime" <= 12 THEN 'AM'
WHEN "StartTime" >= 12 AND "EndTime" <= 17 THEN 'PM'
ELSE 'UNKNOWN'
END "Session"
FROM "TEST"
WHERE ("StartTime" >= 8 AND "EndTime" <= 12)
OR
("StartTime" >= 12 AND "EndTime" <= 17)
UNION ALL
SELECT "Meeting", "From", "EndTime", "StartTime", "Session"
FROM
"TEST",
(SELECT
CASE
WHEN level=1 THEN 'AM'
WHEN LEVEL=2 THEN 'PM'
END "Session"
FROM dual CONNECT BY level < 3)
WHERE
"StartTime" < 12 AND "StartTime" >= 8 AND
"EndTime" > 12 AND "EndTime" <= 17
使用两个子查询(省略并集)的更紧凑的解决方案。 第一个用于映射 table,提供一对一连接或拆分为两条记录。 第二个子查询转换你的日期源添加 "Duration" 键,代表 树状案例:仅上午、仅下午或上午 + 下午 剩下的就是一个简单的连接。
with join_helper as (
select 'AM' "Duration", 'AM' "Session" from dual union all
select 'PM' "Duration", 'PM' "Session" from dual union all
select 'AM-PM' "Duration", 'AM' "Session" from dual union all
select 'AM-PM' "Duration", 'PM' "Session" from dual),
session_duration as (
select test.*,
CASE
WHEN "StartTime" < 12 AND "EndTime" >= 12 THEN 'AM-PM'
WHEN "StartTime" < 12 THEN 'AM'
WHEN "EndTime" >= 12 THEN 'PM'
END "Duration"
from test)
select a."Meeting", a."From",a."StartTime",a."EndTime", b."Session"
from session_duration a, join_helper b
where a."Duration" = b."Duration"
;
您可能会发现查询中的逻辑不那么分散..
SELECT "Meeting","From","EndTime","StartTime" ,
CASE
WHEN "StartTime" >= 8 THEN 'AM'
END "Session"
FROM "TEST"
union all
SELECT "Meeting","From","EndTime","StartTime" ,
CASE
WHEN "EndTime" <= 17 THEN 'PM'
END "Session"
FROM "TEST"
where "StartTime" <12 AND "EndTime" <= 17 ;