Oracle 使用PL/SQL游标返回报表工具的结果集

Oracle 使用PL/SQL游标返回报表工具的结果集,oracle,plsql,reporting,toad,toad-data-point,Oracle,Plsql,Reporting,Toad,Toad Data Point,我是一名报告作者。我的查询通常是来自某个源(在本例中为Oracle Exadata)的SELECT语句,该语句从一个或多个表、联接、WHERE中的过滤器、WHERE中的其他过滤器组等中进行选择。我通常对连接到的任何源都具有只读权限。因此,我无法创建存储过程、包或函数 我需要在复杂查询上使用高级功能,使用FOR..LOOPs、IF-THEN-ELSE结构等来优化导出结果集,以便输出到报告工具(如Qlikview或Tableau) 在我学习的过程中,我发现了许多关于在复杂逻辑结构中使用游标的课程,但

我是一名报告作者。我的查询通常是来自某个源(在本例中为Oracle Exadata)的SELECT语句,该语句从一个或多个表、联接、WHERE中的过滤器、WHERE中的其他过滤器组等中进行选择。我通常对连接到的任何源都具有只读权限。因此,我无法创建存储过程、包或函数

我需要在复杂查询上使用高级功能,使用FOR..LOOPs、IF-THEN-ELSE结构等来优化导出结果集,以便输出到报告工具(如Qlikview或Tableau)

在我学习的过程中,我发现了许多关于在复杂逻辑结构中使用游标的课程,但每一堂课都使用dbms_output.put_line作为每次迭代的结果。输出结果在缓冲区中结束,而不是结果集。我了解到SYS_REFCURSOR是指向结果集的指针。听起来很有希望,但所有示例都是从创建或替换过程/包开始的

如果我解释我想要的结果是什么,我希望你能填补我的理解上的空白:

我有一个复杂的查询,它通过联合多个SELECT语句来合成它们,在Join和Where子句中使用子SELECT等。它返回一个几乎完整的结果集,但在将结果集发送到报告工具之前,我需要进一步细化它

我可以:

DECLARE
  CURSOR current_Schedule IS
  SELECT --insert complex query here-- ;

  row_Schedule  cur_Schedule%ROWTYPE;

BEGIN
  IF NOT current_Schedule%ISOPEN THEN
    OPEN current_Schedule;
  END IF;

  LOOP
    FETCH current_Schedule INTO row_Schedule;
    EXIT WHEN current_Schedule%NOTFOUND;
    --Here's where I think my question is....
    dbms_output.put_line('row_Schedule.Login ' || row_Schedule.Code)
  END LOOP;

EXCEPTION --put exception clause here

END;
这是有效的,验证了我可以迭代复杂查询、更新、筛选等结果的概念。但问题是

它输出到缓冲区,而不是结果集

很可能我误解了一些PL/SQL概念。我在这里找到的所有研究示例和其他来源都假设用户有能力创建函数、包等

我仅限于从QlikView ODBC连接以脚本的形式启动它,该连接对源代码具有只读权限

鉴于我的局限性,是否有解决方案

感谢您花时间阅读本文,如果您能提供一个连贯的答案,我将不胜感激

mfc


编辑:附加信息

我使用的是一个劳动力管理模式,非标准化,位于Exadata数据湖中。我有两个表DET_SEG(详细段)和GEN_SEG(一般段)。DET_SEG包含fk到员工和段代码表、NOM_日期、开始时刻和停止时刻。代码有两种类型,加法和减法。加法代码是指员工分配到的业务部门的工作代码,减法代码是指让员工下班的任何类型的代码,如休息、午餐、病假等。所有代码都绑定到一个表上,该表生成30分钟的时间间隔。由于代码可以占用一个完整的或部分的时间间隔,并且它们可以跨越多个时间间隔,因此我最终需要解决6个独特的用例:之前开始、占用整个时间间隔并在后续时间间隔结束的代码就是其中之一。先开始,后结束的代码是另一种代码。 你可以想象剩下的,我不再重复了。最终输出生成一个名为“分钟”的计算列,指示加法或减法代码在间隔中占用的时间量

我最终创建了6个独特的选择块并在一起,输出倒数第二个解决方案。下面是一个较短的SELECT的示例:

SELECT 
  cal.GlobalIntervals AS G_Intervals,
  mainstart.startmoment AS StartMoment,
  mainstart.stopmoment AS StopMoment,
  mainstart.code as Code,
  mainstart.ID AS Login,
  ((case mainstart.code
        when 'BRK1' then round(24*60*(mainstart.startmoment -mainstart.stopmoment),0)
        when 'BRK2' then round(24*60*(mainstart.startmoment - mainstart.stopmoment),0)
        when 'BRK3' then round(24*60*(mainstart.startmoment - mainstart.stopmoment),0)
        else round(24*60*(mainstart.startmoment - mainstart.stopmoment),0)
  end)) as Minutes  
from
(
SELECT
    (
    to_date(to_char((
    SELECT CLNDR_DT
    FROM COMMOBJ.DIM_DATE
    where CLNDR_DT = trunc(sysdate)
    ), 'dd-mon-yyyy') || HOUR_24_LABEL_CD, 'dd-mon-yyyy hh24:mi:ss')
    ) as GlobalIntervals
FROM    COMMOBJ.DIM_TIME t
WHERE   second_nbr = 0
AND     mod(minute_nbr, 30) = 0 
) cal
left outer join
(
  SELECT DISTINCT
        New_time(to_date(30121899,'ddMMyyyy')+EWFM.DET_SEG.START_MOMENT/1440,'GMT','PST') as StartMoment,
    New_time(to_date(30121899,'ddMMyyyy')+EWFM.DET_SEG.STOP_MOMENT/1440,'GMT','PST') as StopMoment,
    SEG_CODE.CODE,
    SEG_CODE.DESCR,
    EMP.ID,
    EMP.LAST_NAME,
    EMP.FIRST_NAME 
FROM EWFM.DET_SEG DET_SEG
    INNER JOIN EWFM.SEG_CODE SEG_CODE ON (DET_SEG.SEG_CODE_SK = SEG_CODE.SEG_CODE_SK)
    INNER JOIN EWFM.EMP EMP ON (DET_SEG.EMP_SK = EMP.EMP_SK)
    INNER JOIN SBCG_ADHOC.SBCG_STAFF SBCG_STAFF ON (EMP.ID = SBCG_STAFF.AGENT_LOGIN)
    WHERE trunc (New_time(to_date(30121899,'ddMMyyyy')+EWFM.DET_SEG.START_MOMENT/1440,'GMT','PST')) =  trunc(sysdate)  
    and EWFM.SEG_CODE.CRNT_REC_IND = 'Y'
    and SEG_CODE.CODE NOT IN ('SHIFT', 'CCBOUT', 'HOLIDA', 'LIND', 'PCHT', 'PIND', 'PXTR', 'LCHT', 'LXTR', 'PSVC', 'HV Saves Inbound' )
  )mainstart
  --StartMoment occurs AFTER Current Interval
  on  cal.GlobalIntervals < mainstart.StartMoment 
  --StopMoment occurs on Next Interval 
  and (cal.GlobalIntervals + (1/24/60 * 30)) = mainstart.StopMoment 
  --StartMoment occurs prior to Next Interval
  and mainstart.StartMoment < (cal.GlobalIntervals + (1/24/60 * 30))
选择
cal.GlobalIntervals作为G_间隔,
mainstart.startmoment作为startmoment,
主起动停止力矩作为停止力矩,
主程序代码作为代码,
mainstart.ID作为登录名,
((第1部分代码)
当“BRK1”时,则为四舍五入(24*60*(主起动时刻-主起动停止时刻),0)
当“BRK2”时,则为四舍五入(24*60*(主起动时刻-主起动停止时刻),0)
当“BRK3”时,然后旋转(24*60*(主起动时刻-主起动停止时刻),0)
其他四舍五入(24*60*(主起动时刻-主起动停止时刻),0)
以分钟结束
从…起
(
挑选
(
截止日期((
选择CLNDR\u DT
从COMMOBJ.DIM_日期开始
其中CLNDR_DT=trunc(sysdate)
),'dd-mon-yyyyy')| |小时|标签(CD,'dd-mon-yyyyy hh24:mi:ss')
)作为全球干预
来自COMMOBJ.DIM_TIME t
其中第二个\u nbr=0
和mod(分钟数,30)=0
)卡尔
左外连接
(
选择不同的
新时间(截止日期(30121899,'ddMMyyyy')+EWFM.DET段开始时刻/1440,'GMT','PST')作为开始时刻,
新时间(截止日期(30121899,'ddMMyyyy')+EWFM.DET段停止时刻/1440,'GMT','PST')作为停止时刻,
SEG_CODE.CODE,
SEG_CODE.DESCR,
EMP.ID,
皇帝姓,
皇帝的名字
来自EWFM.DET_SEG DET_SEG
内部连接EWFM.SEG_代码SEG_代码ON(DET_SEG.SEG_代码_SK=SEG_代码SEG_SK)
内部连接EWFM.EMP EMP ON(DET_SEG.EMP_SK=EMP.EMP_SK)
内部连接SBCG_ADHOC.SBCG_STAFF SBCG_STAFF ON(EMP.ID=SBCG_STAFF.AGENT_登录)
其中trunc(新时间(截止日期(30121899,'ddMMyyyy')+EWFM.DET_段开始时刻/1440,'GMT','PST'))=trunc(系统日期)
和EWFM.SEG_CODE.CRNT_REC_IND='Y'
和SEG_CODE.CODE不在('SHIFT'、'ccabout'、'HOLIDA'、'LIND'、'PCHT'、'PIND'、'PXTR'、'LCHT'、'LXTR'、'PSVC'、'HV Saves Inbound')
)主流艺术
--开始时刻发生在当前间隔之后
关于cal.GlobalIntervals
输出如下所示:

G|U间隔|开始时刻|停止时刻|代码|登录|分钟数
4/17/17 12:00 | 2/17/17 12:00 | 2/17/17 12:15 | BRK1 | ABC123 |-15
4/17/17 12:00 | 2/17/17 12:00 | 2/17/17 08:00 | SHIFT | XYZ321 | 30
2017年4月17日12:30 | 2017年2月17日12:45 | 2017年2月17日01:45 |午餐| LK4567 |-15

分钟列的Case语句随着每个用例的变化而变化,就像最终联接中的ON条件一样。虽然它可能不是最有效的,但它生成的数据集几乎已经准备就绪