Oracle使用子句嵌套

时间:2015-07-06 18:38:19

标签: sql oracle common-table-expression

我需要在符合某个标准的情况下将一条记录拆分为2条,并且在将它们拆分后很难将它们连接在一起。 我有这张桌子:

enter image description here

对于那天的会议,我需要将它们分成两个会话,一个在早上,一个在下午。在这个例子中,我需要将测试2分成2个会话AM和PM。

enter image description here

我已经使用了这个陈述,它很适合我:

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

我该如何解决这个问题? 请查找附带的脚本以创建表格和相关数据。

  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);

我的目标是获得此输出

enter image description here

以及这个一对一视图

enter image description here

3 个答案:

答案 0 :(得分:2)

你并没有真正用两个子句嵌套,但是你在一个联盟中嵌套一个。

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 

答案 1 :(得分:1)

使用两个子查询(省略联合)的更紧凑的解决方案。 映射表的第一个,提供一对一的连接或两个记录中的拆分。 第二个子查询转换您的日期源,添加“持续时间”键,表示 树案例:仅AM,仅PM或AM + PM 其余的是一个简单的连接。

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"  
;

你可能会发现查询中的逻辑分散了..

答案 2 :(得分:1)

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 ;