在单个 oracle sql 语句中返回多个值
Posted
技术标签:
【中文标题】在单个 oracle sql 语句中返回多个值【英文标题】:Return multiple values in a single oracle sql statement 【发布时间】:2016-11-01 20:46:38 【问题描述】:下面是java中的查询
SELECT achieve_STATUS_CD
FROM achievemnt
WHERE env_id = '?' AND ROWNUM = 1
ORDER BY achive_status_dt
需要根据另外两个表注册返回值'Y',提供以下条件
-
enrollment.achieve_intent = '2'
注册.BEGIN_DT >=
迄今为止 (
2011 年 5 月 1 日,
'MM/DD/YYYY')
3.provision.RELEASE_DT
对于其余所有条件,它应该返回原始查询中的值(SELECT perform_STATUS_CD FROM achievementmnt WHERE env_id = '?' AND ROWNUM = 1 ORDER BY achive_status_dt)
achievemnt 是注册的子表
这个逻辑怎么写?
我已经编写了下面的查询,但它在 2 个地方有 env_id,但我们现在无法在我们的 java 中更改它,所以我需要编写一个仅一次接受 env_id 的查询
WITH TMP
AS (SELECT 'Y' AS achieve_STATUS_CD, env_id
FROM enrollment r, provision a
WHERE r.prov_id = a.prov_id
AND r.achieve_intent = '2'
AND a.BEGIN_DT >=
TO_DATE (
05/01/2011,
'MM/DD/YYYY')
AND a.RELEASE_DT <= SYSDATE AND R.env_ID = '?')
SELECT NVL (F.achieve_STATUS_CD,TMP.achieve_STATUS_CD)
FROM TMP FULL OUTER JOIN
(SELECT achieve_STATUS_CD
FROM achievemnt
WHERE env_id = '?' AND
ROWNUM = 1
ORDER BY achive_status_dt
) F
ON TMP.env_ID = F.env_ID;
【问题讨论】:
首先,我怀疑您的初始查询不正确。rownum = 1
谓词将在 order by
之前应用,因此您可以选择首先遇到的任意行并对该行进行排序。您似乎可能想要第一个 achive_status_dt
行中的值。我不确定我是否理解你的其余问题。如果您只希望使用单个绑定变量的最后一个查询的逻辑,只需创建另一个 CTE,从 dual 中选择绑定值并在其余查询中尽可能多次引用该 CTE。
你能告诉我如何使用 CTE 从 dual 中选择绑定值,我可以参考
这是在 Oracle 中
【参考方案1】:
您的初始查询很可能不正确。此查询中的rownum = 1
谓词在ORDER BY
之前应用,因此您要求任意行,其中env_id
是任意绑定值,然后对生成的单行进行排序。对单行进行排序显然是没有意义的。
SELECT achieve_STATUS_CD
FROM achievemnt
WHERE env_id = '?'
AND ROWNUM = 1
ORDER BY achive_status_dt
如果您想对多行进行排序并选择第一个 achive_status_dt
的行,您需要类似
SELECT *
FROM (SELECT achieve_STATUS_CD
FROM achievemnt
WHERE env_id = '?'
ORDER BY achive_status_dt) a
WHERE a.ROWNUM = 1
但是,如果您的实际问题是第二个查询执行您想要的操作(鉴于我刚才提到的问题,这似乎不太可能)但您想使用单个绑定变量来执行此操作,您可以简单地添加另一个 CTE 来选择dual
中的绑定变量,然后在任何你喜欢的地方引用该 CTE
WITH env
AS (SELECT '?' env_id from dual)
,TMP
AS (SELECT 'Y' AS achieve_STATUS_CD, env_id
FROM enrollment r, provision a, env
WHERE r.prov_id = a.prov_id
AND r.achieve_intent = '2'
AND a.BEGIN_DT >=
TO_DATE (
05/01/2011,
'MM/DD/YYYY')
AND a.RELEASE_DT <= SYSDATE
AND R.env_ID = env.env_ID)
SELECT NVL (F.achieve_STATUS_CD,TMP.achieve_STATUS_CD)
FROM TMP FULL OUTER JOIN
(SELECT achieve_STATUS_CD
FROM achievemnt
join env
on achievement.env_id = env.env_id
WHERE ROWNUM = 1
ORDER BY achive_status_dt
) F
ON TMP.env_ID = F.env_ID;
【讨论】:
感谢贾斯汀,它成功了,我学会了如何使用上述方法只使用一次绑定变量【参考方案2】:假设:
1- rownum 的问题是正确的(我同意 Justin)
2- 总是填充成就表
你可以解除条件
AND R.env_ID = '?'
关于 TMP 子查询。 在这种情况下,查询是基于 env_id 的 LEFT 外连接就足够了。
所以完整的查询应该变成这样(我没有sql控制台来测试它)
WITH TMP
AS (SELECT 'Y' AS achieve_STATUS_CD, env_id
FROM enrollment r, provision a
WHERE r.prov_id = a.prov_id
AND r.achieve_intent = '2'
AND a.BEGIN_DT >=
TO_DATE (
05/01/2011,
'MM/DD/YYYY')
AND a.RELEASE_DT <= SYSDATE ),
F
AS (SELECT TMP.achieve_STATUS_CD
FROM achievemnt
WHERE env_id = '?' AND
ROWNUM = 1
ORDER BY achive_status_dt)
SELECT NVL (TMP.achieve_STATUS_CD, F.achieve_STATUS_CD)
FROM F LEFT OUTER JOIN TMP
ON F.env_ID=TMP.env_ID;
请注意,我反转了 NVL 字段:如果 TMP.achieve_STATUS_CD 不为空,即如果存在一行,则应采用始终为 Y 的值,否则采用来自成就的值。
如果假设 2 不正确,您可以反转外连接中的 2 个子查询。
如果你需要最旧日期的成就记录,F可能会变成这样
SELECT TMP.achieve_STATUS_CD, achive_status_dt, env_id, min(achive_status_dt) OVER(partition by end_id) min_date
FROM achievemnt
WHERE env_id = '?' AND
achive_status_dt=min_date
【讨论】:
【参考方案3】:这就是我对您的问题的理解(我可能完全错了):如果 env_id 显示“Y”至少存在一个符合您条件的注册/提供对,否则显示它的第一个成就状态。
select
case when exists
(
select *
from enrollment e
join provision p on p.prov_id = e.prov_id
where e.achieve_intent = '2'
and p.begin_dt >= date '2011-05-01'
and p.release_dt <= sysdate
and e.env_id = :env_id
) then 'Y'
else
(
select max(achieve_status_cd) keep (dense_rank first order by achive_status_dt)
from achievement
where env_id = :env_id
) as status
from dual;
如果您希望 :env_id 在查询中只包含一次,请将其稍微更改为:
select
case when exists
(
select ...
and e.env_id = main.env_id
) then 'Y'
else
(
select ...
where env_id = main.env_id
) as status
from (select :env_id as env_id from dual) main;
【讨论】:
感谢 Thorsten,为我提供了替代解决方案。以上是关于在单个 oracle sql 语句中返回多个值的主要内容,如果未能解决你的问题,请参考以下文章