SQL*加上Spool Oracle(子查询/With子句问题)

SQL*Plus Spool Oracle ( Subquery /With Clause Issue)

你能帮帮我吗?

当我在 Toad 中执行下面的 .sql 文件时,它给了我预期的结果。

 with 
    a as(select extract(year from sysdate)var_year,to_char(sysdate,'mm-dd')var_day from dual),
    b as(select case when var_day between '10-01'and '12-31'
    then to_date(var_year||'-10-01','yyyy-mm-dd')
    else to_date(var_year-1||'-10-01','yyyy-mm-dd')end d1,
    case when var_day between'10-01'and'12-31'
    then to_date(var_year+1||'-09-30','yyyy-mm-dd')
    else to_date(var_year||'-09-30','yyyy-mm-dd')end d2
    from a)
    select * from b,SCHEMA.TABLE1
    where SCHEMA.TABLE1.DATE_FRAIS between b.d1 and b.d2;

但是当我尝试使用添加假脱机功能的 .cmd 作业启动它时,控制台打开但没有任何反应并且控制台保持打开状态。生成了 .csv 文件,但里面没有任何内容。

请在下面找到脚本不工作(假脱机成功但没有内容):

SET FEEDBACK OFF
set heading on
SET PAGESIZE 0
SET LINESIZE 8000
set pagesize 50000
SET COLSEP ";"
COLUMN dcol new_value mydate noprint
select to_char(sysdate,'YYYY_MM_DD') dcol from dual;
SPOOL test.csv;
with 
a as(select extract(year from sysdate)var_year,to_char(sysdate,'mm-dd')var_day from dual),
b as(select case when var_day between '10-01'and '12-31'
then to_date(var_year||'-10-01','yyyy-mm-dd')
else to_date(var_year-1||'-10-01','yyyy-mm-dd')end d1,
case when var_day between'10-01'and'12-31'
then to_date(var_year+1||'-09-30','yyyy-mm-dd')
else to_date(var_year||'-09-30','yyyy-mm-dd')end d2
from a)
select * from b,SCHEMA.TABLE1
where SCHEMA.TABLE1.DATE_FRAIS between b.d1 and b.d2;
SPOOL OFF

然而,当我通过添加假脱机功能的 .cmd 作业启动 "simple" .SQL 文件时,它起作用了(可能是因为我删除了 "CASE" ?)。生成csv文件,里面有内容

请在下面找到脚本工作的示例(假脱机内容成功):

    SET FEEDBACK OFF
set heading on
SET PAGESIZE 0
SET LINESIZE 8000
set pagesize 50000
SET COLSEP ";"
COLUMN dcol new_value mydate noprint
select to_char(sysdate,'YYYY_MM_DD') dcol from dual;
SPOOL test.csv;
with
a as (select extract(year from sysdate) var_year1, extract(year from sysdate) var_year2, to_char(sysdate) var_day from dual)
select * from a;
SPOOL OFF

会不会只是您的查询需要很长时间才能检索到所有结果,而您还没有保留足够长的时间?您可能会在 Toad 中看到结果,但您是否尝试过转到结果集的末尾,而不是仅仅获取前 500 行(或者无论您将 Toad 设置为每次提取检索多少行)。

我怀疑这个问题与 WITH 子句有关。无论如何,没有必要;您可以像这样简单地操作 sysdate,以获得结果:

select *
from   SCHEMA.TABLE1 t1
where  t1.DATE_FRAIS between add_months(trunc(add_months(sysdate, 3), 'yyyy'), -3) 
                     and     add_months(trunc(add_months(sysdate, 3), 'yyyy'), 9) -1;

N.B。我希望您的 DATE_FRAIS 列没有时间元素,否则您将遗漏每年 9 月 30 日午夜之后的任何内容。

我怀疑 (a) 你 运行 this as sqlplus -s user/pass @script 并且在你的脚本末尾没有 exit,这将导致命令 window 保持开放; (b) 对于今年的日期 运行ge,您的 table 中没有任何已提交的数据。如果您在 Toad 会话中添加数据并在那里 运行 您的查询,但没有提交这些更改,您会看到这种效果 - 在这种情况下,新插入的数据对任何其他会话都不可见,因此您的 SQL*Plus 查询不会看到它。由于您关闭了反馈,您甚至不会看到“未选择任何行”。


@boneist 的简化比我的更清晰、更简单,但我会留下这个来展示 CTE 和非 CTE,以及 between>=/< 变体.

顺便说一下,您可以大大简化日期计算,例如:

with b as (
  select add_months(trunc(sysdate, 'YYYY'),
      case when extract(month from sysdate) < 10 then -3 else 9 end) d1,
    last_day(add_months(trunc(sysdate, 'YYYY'),
      case when extract(month from sysdate) < 10 then 8 else 20 end)) d2
  from dual
)
select *
from b
join table1 on table1.date_frais between b.d1 and b.d2;

您可以使用 this demo. I think that's what you're after, if I've interpreted your current query properly. (And here is the same query with @boneist's simplification) 查看 CTE 为各种日期生成的开始和结束日期。

或者如果您真的不想显示日期 运行ge 以及来自 table1 的实际数据,请将计算移到过滤器中:

select * -- but still better to list the columns
from table1
where date_frais >= add_months(trunc(sysdate, 'YYYY'),
      case when extract(month from sysdate) < 10 then -3 else 9 end)
and date_frais < add_months(trunc(sysdate, 'YYYY'),
      case when extract(month from sysdate) < 10 then 9 else 21 end);

我还将此版本从 between 更改为使用 >=<,并将结束日期推迟了一天;这将包括最后一个月最后一天的任何值,这些值在午夜之后有时间(我看到@boneist 也对此发表了评论)。如果你的日期都是午夜,那么 between 就可以了,但我仍然更喜欢这种明确的模式,我认为它也使月份调整计算更加明显。