Oracle SQL 中的变量声明、CTE 和 While 循环
Posted
技术标签:
【中文标题】Oracle SQL 中的变量声明、CTE 和 While 循环【英文标题】:Variables Declaration, CTEs, and While Loops in Oracle SQL 【发布时间】:2021-10-10 13:03:44 【问题描述】:所以我可能会被一些非常琐碎的事情困住,但无法弄清楚如何让它发挥作用。我创建了 2 个在 SQL 中工作的代码块,但在 Oracle SQL 中的日期变量声明存在一些问题。
我在创建这些代码时拥有对 SQL 数据库的写入权限,因此我执行了“插入”来创建临时表。我没有写权限了。所以我正在使用 CTE。
原始代码如下所示:
DECLARE @Startdate Datetime = '2021-Jun-01 00:00:00.000'
DECLARE @Enddate Datetime = '2021-Jun-30 00:00:00.000'
Insert into Temp1
select ...
from ...
WHILE Startdate <= Enddate
BEGIN
Insert into Temp2
select ...
from (Temp 1)
left join
select ...
set @startdate=dateadd(d,1,@startdate)
end;
使用我的新代码,我做了以下调整:
VARIABLE Startdate Datetime = '2021-Jun-01 00:00:00.000'
VARIABLE Enddate Datetime = '2021-Jun-30 00:00:00.000'
EXEC :Startdate := '2021-Jun-30 00:00:00.000'
EXEC :Enddate := '2021-Jun-30 00:00:00.000'
WITH Temp1 as (
select ...
from ...),
/* Unsure about using WHILE with with 2 CTEs so removing them for now but will need to be added*/
WITH Temp2 as
select ...
from (Temp 1)
left join
select ...
set startdate = :startdate + 1
end)
select * from Temp2;
这两个代码块可以完美地单独工作。我认为我的担忧在于以下一项或全部:
-
变量声明 - 我阅读了几篇 *** 帖子,似乎有绑定变量和替换变量。有没有其他声明变量的方法?
2 个 CTE 之间的 WHILE 循环。我们可以做一个while循环作为CTE吗? (与此类似)create while loop with cte
如何增加日期。这是在 Oracle PL/SQL 中增加日期的正确方法吗?
任何指导都会有所帮助。
另外加2块代码供参考:
表格详情:
交易 - 包含交易信息。 Execution Date 是事务执行的时间戳
帐户 - 包含帐户信息,每个帐户都有一个唯一的 Account_Key
Code_Rel - 将交易代码映射到交易类型
Group Rel - 将事务类型映射到事务组
/***Block 1 of Code***/
insert into Temp1
select
a.ACCOUNT_KEY
,a.SPG_CD
,t.EXECUTION_DATE
from Schema_Name.TRANSACTIONS t
inner join Schema_Name.ACCOUNT a on a.en_sk=t.ac_sk
inner join Schema_Name.Code_Rel tr on t.t_cd_s = tr.t_cd_s
inner join ( select * from Schema_Name.Group_Rel
where gtrt_cd in ('Type1','Type2')) tt on tr.trt_cd = tt.trt_cd
where t.EXECUTION_DATE >= @startdate and t.EXECUTION_DATE<=@EndDt
and tt.gtrt_cd in ('Type1','Type2')
group by a.ACCOUNT_KEY ,a.SPG_CD, t.EXECUTION_DATE;
/***WHILE LOOP***/
while @startdate <= @EndDt
BEGIN
/***INSERT AND BLOCK 2 OF CODE***/
insert into Temp2
select table1.account_key, table1.SPG_CD, @startdate, coalesce(table2.sum_tr1,0),coalesce(table3.sum_tr2,0),
case when coalesce(table3.sum_tr2,0)>0 THEN coalesce(table2.sum_tr1,0)/coalesce(table3.sum_tr2,0) ELSE 0 END,
case when coalesce(table3.sum_tr2,0)>0 THEN
CASE WHEN coalesce(table2.sum_tr1,0)/coalesce(table3.sum_tr2,0)>=0.9 and coalesce(table2.sum_tr1,0)/coalesce(table3.sum_tr2,0)<=1.10 and coalesce(table2.sum_tr1,0)>=1000 THEN 'Yes' else 'No' END
ELSE 'No' END
FROM ( SELECT * FROM Temp1 WHERE execution_date=@startdate) TABLE1 LEFT JOIN
(
select a.account_key,a.SPG_CD, SUM(t.AC_Amt) as sum_tr1
from Schema_Name.TRANSACTIONS t
inner join Schema_Name.ACCOUNT a on a.en_sk=t.ac_sk
inner join Schema_Name.Code_Rel tr on t.t_cd_s = tr.t_cd_s
inner join ( select * from Schema_Name.Group_Rel
where gtrt_cd in ('Type1')) tt on tr.trt_cd = tt.trt_cd
where t.EXECUTION_DATE <= @startdate
and t.EXECUTION_DATE >=dateadd(day,-6,@startdate)
and tt.gtrt_cd in ('Type1')
group by a.account_key, a.SPG_CD
) table2 ON table1.account_key=table2.account_key
LEFT JOIN
(
select a.account_key,a.SPG_CD, SUM(t.AC_Amt) as sum_tr2
from Schema_Name.TRANSACTIONS t
inner join Schema_Name.ACCOUNT a on a.en_sk=t.ac_sk
inner join Schema_Name.Code_Rel tr on t.t_cd_s = tr.t_cd_s
inner join ( select * from Schema_Name.Group_Rel
where gtrt_cd in ('Type2')) tt on tr.trt_cd = tt.trt_cd
where t.EXECUTION_DATE <= @startdate
and t.EXECUTION_DATE >=dateadd(day,-6,@startdate)
and tt.gtrt_cd in ('Type2')
group by a.account_key, a.SPG_CD ) table3 on table1.account_key=table3.account_key
where coalesce(table2.sum_tr1,0)>=1000
set @startdate=dateadd(d,1,@startdate)
end;
【问题讨论】:
【参考方案1】:您不需要使用 PL/SQL 或 WHILE
循环或声明变量,并且可能在单个 SQL 查询中使用子查询因式分解子句(和递归)来生成递增日期的日历。像这样虚构的例子:
INSERT INTO temp2 (col1, col2, col3)
WITH time_bounds(start_date, end_date) AS (
-- You can declare the bounds in the query.
SELECT DATE '2021-06-01',
DATE '2021-06-30'
FROM DUAL
),
calendar (dt, end_date) AS (
-- Recursive query to generate a row for each day.
SELECT start_date, end_date FROM time_bounds
UNION ALL
SELECT dt + INTERVAL '1' DAY, end_date
FROM calendar
WHERE dt + INTERVAL '1' DAY <= end_date
),
temp1 (a, b, c) AS (
-- Made-up query
SELECT a, b, c FROM some_table
),
temp2 (a, d, e) AS (
-- Another made-up query.
SELECT t1.a,
s2.d,
s2.e
FROM temp1 t1
LEFT OUTER JOIN some_other_table s2
ON (t1.b = s2.b)
)
-- Get the values to insert.
SELECT t2.a,
t2.d,
t2.e
FROM temp2 t2
INNER JOIN calendar c
ON (t2.e = c.dt)
WHERE a BETWEEN 3.14159 AND 42;
如果您尝试在 PL/SQL 循环中使用多个插入来执行此操作,那么它将比单个语句慢得多。
【讨论】:
感谢您分享此内容。绝对看起来更干净。我正在尝试查看这是否有效,但第一个代码块(标记为 Temp1)从执行日期>开始日期和执行日期 @Dhruv 我不知道,因为我没有看到你的代码。你的问题用...
替换了所有的实现细节,所以我不得不为答案做了一切,并猜测你的要求是什么。如果您edit您的问题提供了您的表的详细信息和可执行查询,那么我们可以回复。
明白了。我已将代码添加到我原来的问题中。让我知道现在是否更有意义?以上是关于Oracle SQL 中的变量声明、CTE 和 While 循环的主要内容,如果未能解决你的问题,请参考以下文章
oracle sql语法 ①中的:1代表啥;②中声明的变量类型是啥;③中的赋值语法是啥
在 Oracle SQL 中使用 CTE(ORA-00923:在预期的地方找不到 FROM 关键字)
将表中的单个值分配给 ORACLE PL/SQL 中声明的变量时出错