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 ;