【问题标题】:SQL*Plus Spool Oracle ( Subquery /With Clause Issue)SQL*Plus Spool Oracle(子查询/With 子句问题)
【发布时间】:2015-07-30 06:23:26
【问题描述】:

你能帮帮我吗?

当我在 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 作业启动“简单”.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

【问题讨论】:

  • 如果您从 SQL*Plus 命令行运行“非工作”查询,您会得到什么?
  • 您的 .cmd 文件如何启动 SQL*Plus 并使用 @ 运行脚本?你的脚本末尾有exit 吗?
  • 您的table1 是否实际上具有您可以从 SQL*Plus 中看到的匹配数据 - 或者您是否可能通过查询工作的同一个 Toad 会话插入了一些数据,但尚未提交?我怀疑这两个问题 - 未提交的数据和脚本没有退出。请提供更多详细信息。您还可以大大简化您正在做的事情。
  • @Politank-Z :如果您从 SQL*Plus 命令行运行“非工作”查询 => 控制台打开,但没有任何反应,控制台保持打开状态,而查询工作正常,我看到了SQL行的处理。
  • @AlexPoole:Cmd 使用以下命令启动 SQL*plus:sqlplus username/password@databasename @"c:\my_script.sql"。不,最后没有出口。但问题不是控制台保持打开状态,而是控制台中的行没有像我的示例工作脚本那样处理(在我最初的问题中描述)

标签: oracle csv sqlplus spool


【解决方案1】:

我怀疑 (a) 您以 sqlplus -s user/pass @script 运行它并且脚本末尾没有 exit,这将导致命令窗口保持打开状态; (b) 在今年的日期范围内,您的表中没有任何已提交的数据。如果您在 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 查看 CTE 为各种日期生成的开始日期和结束日期。我想这就是你所追求的,如果我有 interpreted your current query 正确的话。 (还有here is the same query with @boneist's simplification)。

或者,如果您真的不想显示日期范围以及来自 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 更改为使用&gt;= 和&lt;,并将结束日期推迟了一天;这将包括最后一个月最后一天午夜之后的任何值(我看到@boneist 也对此发表了评论)。如果你的日期都是午夜,那么between 会起作用,但我仍然更喜欢这种明确的模式,而且我认为它使月份调整计算更加明显。

【讨论】:

    【解决方案2】:

    难道仅仅是您的查询需要很长时间才能检索到所有结果,而您没有留下足够长的时间吗?您可能会在 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;
    

    注意我希望您的 DATE_FRAIS 列中没有时间元素,否则您将错过每年 9 月 30 日午夜之后的任何内容。

    【讨论】:

    • 思维相似,至少在简化方面;但 OP 的范围根据当月涵盖不同的年份,因此在 11 月运行的查询将涵盖 10 月 15 日至 9 月 16 日,您没有处理。并且 OP 还在选择列表中包含 b 列和 *,但不确定这是否完全是故意的......但如果没有 CTE,如果需要,您需要重复计算。
    • 我的计算按预期工作;你试过用 11 月的日期替换 sysdate 吗?至于出现在选择中的列 - 如果这是 OP 想要的,我同意 CTE 将是处理它的最佳方式,但它可能只是选择上述两个日期计算,而不是 OP 的案例陈述最初使用。
    • 哈,不,尽管演示了 OP 的版本和我的版本,但由于某种原因我没有尝试你的版本。我完全错过了嵌套的 add_months 进行调整,比我的方式更整洁(而且更微妙......)。对不起,你是quite right, of course。好吧,很遗憾,我不能再投票了。
    • 我喜欢日期算术 *{:-) (注意,那是 date 算术。timestamp 算术可以从一个短码头走很长一段路就我而言!)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-18
    • 2016-04-25
    • 1970-01-01
    • 1970-01-01
    • 2021-12-14
    • 2021-08-09
    相关资源
    最近更新 更多