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
就可以了,但我仍然更喜欢这种明确的模式,我认为它也使月份调整计算更加明显。
你能帮帮我吗?
当我在 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
就可以了,但我仍然更喜欢这种明确的模式,我认为它也使月份调整计算更加明显。