【问题标题】:Return multiple values in a single oracle sql statement在单个 oracle sql 语句中返回多个值
【发布时间】: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',提供以下条件

  1. enrollment.achieve_intent = '2'
  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 中

标签: sql 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,为我提供了替代解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-08
    • 2016-03-20
    • 2012-09-27
    • 2019-04-19
    • 1970-01-01
    相关资源
    最近更新 更多