简体   繁体   English

在单个oracle sql语句中返回多个值

[英]Return multiple values in a single oracle sql statement

Below is a query that is in java 以下是Java中的查询

SELECT achieve_STATUS_CD
FROM achievemnt
WHERE env_id = '?' AND ROWNUM = 1 
ORDER BY achive_status_dt

which needs to return value 'Y' based from another two tables enrollment, provision with below conditions 需要从另外两个表的注册中返回值“ Y”,并满足以下条件

  1. enrollment.achieve_intent = '2' enrollment.achieve_intent ='2'
  2. enrollment.BEGIN_DT >= TO_DATE ( 05/01/2011, 'MM/DD/YYYY') 3.provision.RELEASE_DT <= SYSDATE enrollment.BEGIN_DT> = TO_DATE(05/01/2011,'MM / DD / YYYY')3.provision.RELEASE_DT <= SYSDATE

for the rest all conditions it should return the values from original query (SELECT achieve_STATUS_CD FROM achievemnt WHERE env_id = '?' AND ROWNUM = 1 ORDER BY achive_status_dt) 对于其余所有条件,它都应返回原始查询的值(SELECT Achieve_STATUS_CD FROM Achievemnt WHERE env_id ='?'AND ROWNUM = 1 ORDER BY achive_status_dt)

achievemnt is child table of enrollment Achievemnt是注册的子表

How can i write this logic ? 我该如何写这个逻辑?

I have written the below query but it has env_id at 2 places but we cant change that in our java for now so i need to write in a single query which accepts env_id only at once 我已经写了下面的查询,但是它在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;

Your initial query is highly likely to be incorrect. 您的初始查询很可能不正确。 The rownum = 1 predicate in this query is applied before the ORDER BY so you're asking for an arbitrary row where the env_id is whatever bind value and then sorting the resulting single row. 此查询中的rownum = 1谓词在ORDER BY之前应用,因此您要询问一个任意行,其中env_id是任何绑定值,然后对所得的单行进行排序。 Sorting a single row is obviously pointless. 排序单行显然是毫无意义的。

SELECT achieve_STATUS_CD
  FROM achievemnt
 WHERE env_id = '?' 
   AND ROWNUM = 1 
 ORDER BY achive_status_dt

If you want to sort multiple rows and to pick the row with the first achive_status_dt , you'd want something like 如果要对多行进行排序并选择第一个achive_status_dt的行,则需要类似

SELECT *
  FROM (SELECT achieve_STATUS_CD
          FROM achievemnt
         WHERE env_id = '?' 
         ORDER BY achive_status_dt) a
 WHERE a.ROWNUM = 1 

If your actual question, though, is that the second query does what you want (which seems unlikely given the issue I just mentioned) but you want to do it with a single bind variable, you can simply add another CTE that selects the bind variable from dual and then reference that CTE wherever you'd like 但是,如果您的实际问题是第二个查询满足您的要求(考虑到我刚才提到的问题,这似乎不太可能),但是您想使用单个绑定变量来执行此操作,则只需添加另一个选择绑定变量的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;

Supposing that : 假设:

1- the question of rownum is correct (i agree with Justin) 1- rownum问题正确(我同意贾斯汀)

2- the achievemnt table is always populated 2-总是填充成就表

You can release the condition 您可以解除条件

AND R.env_ID = '?' AND R.env_ID ='?'

on the TMP subquery. 在TMP子查询上。 In this case, it should be enough that the query is a LEFT outer join based on env_id. 在这种情况下,查询是基于env_id的LEFT外部联接就足够了。

So the full query should become like this (i don't have an sql console to test it) 因此完整的查询应该变成这样(我没有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;

Note that i inverted the NVL fields: if TMP.achieve_STATUS_CD is not null, ie if a row exists, that value, which is always Y, should be taken, otherwise the value from achievemnt. 请注意,我颠倒了NVL字段:如果TMP.achieve_STATUS_CD不为null,即,如果存在一行,则应采用始终为Y的值,否则应采用Achievemnt的值。

If the assuntion 2 is not true, you can invert the 2 subqueries in the outer join. 如果assuntion 2不正确,则可以反转外部联接中的2个子查询。

If you need the record from achievemnt with the oldest date, F may become something like this 如果您需要成就记录中最早的日期,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

This is how I understand your question (and I may be completely wrong): If at least one enrollment/provision pair that matches your criteria exists for an env_id show 'Y', otherwise show the first achievement status for it. 这就是我对您的问题的理解方式(我可能完全错了):如果在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;

If you want to have :env_id only once in your query, change it slightly to: 如果只想在查询中只使用一次: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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM