如果旧版本不可用,请从当月获取行

时间:2016-10-24 12:40:00

标签: sql oracle

我有一个看起来像这样的表:

+--------------------+---------+
|    Month (date)    |  amount |
+--------------------+---------+
| 2016-10-01         | 20      |
| 2016-08-01         | 10      |
| 2016-07-01         | 17      |
+--------------------+---------+

我正在寻找满足以下条件的查询(sql语句):

  • 给我上个月的价值。
  • 如果上一个月没有值,请及时锁定,直到找到一个。
  • 如果当前月份只有一个值,请给我这个值。

在示例表中,我正在寻找的行是:

+--------------------+---------+
| 2016-08-01         | 10      |
+--------------------+---------+

有没有人想过非复杂的选择查询?

提前致谢, 彼得

6 个答案:

答案 0 :(得分:4)

您可能需要以下内容:

SELECT *
  FROM (  SELECT *
            FROM test
           WHERE TRUNC(SYSDATE, 'month') >= month
        ORDER BY CASE
                    WHEN TRUNC(SYSDATE, 'month') = month
                        THEN 0 /* if current month, ordered last */
                        ELSE 1 /* previous months are ordered first */
                    END DESC,
                    month DESC /* among previous months, the greatest first */
       )
 WHERE ROWNUM = 1    

答案 1 :(得分:1)

我会使用row_number()

select t.*
from (select t.*,
             row_number() over (order by (case when to_char(dte, 'YYYY-MM') = to_char(sysdate, 'YYYY-MM') then 1 else 2 end) desc,
                                          dte desc
                               ) as seqnum
      from t
     ) t
where seqnum = 1;

实际上,您不需要row_number()

select t.*
from (select t.*
      from t
      order by (case when to_char(dte, 'YYYY-MM') = to_char(sysdate, 'YYYY-MM') then 1 else 2 end) desc,
               dte desc
     ) t
where rownum = 1;

答案 2 :(得分:1)

使用MAX的另一种方式

WITH tbl AS (
    SELECT TO_DATE('2016-10-01', 'YYYY-MM-DD') AS "month", 20 AS amount FROM dual
    UNION 
    SELECT TO_DATE('2016-08-01', 'YYYY-MM-DD') AS "month", 10 AS amount FROM dual    
    UNION 
    SELECT TO_DATE('2016-07-01', 'YYYY-MM-DD') AS "month", 5 AS amount FROM dual        
)
SELECT * 
  FROM tbl
 WHERE TRUNC("month", 'MONTH') = NVL((SELECT MAX(t."month") 
                                        FROM  tbl t 
                                       WHERE t."month" < TRUNC(SYSDATE, 'MONTH')), 
                                     TRUNC(SYSDATE, 'MONTH'));

答案 3 :(得分:0)

这不是最好的查询,但应该有效。

select amount, date from (
  select amount, date, row_number over(partition by HERE_PUT_ID order by 
    case trunc(date, 'month') when trunc(sysdate, 'month') then to_date('00010101', 'yyyymmdd') else trunc(date, 'month')  end
    desc) r)
where r = 1;

我猜你在表中有一些id,所以如果你想要查询整个表只是删除id列而不是HERE_PUT_ID:partition by HERE_PUT_ID

答案 4 :(得分:0)

我添加了更多用于测试的数据,以及一个&#34; id&#34;列(更现实的场景),以显示这将如何工作。如果没有&#34; id&#34;在您的数据中,只需从解决方案中删除对它的任何引用。

备注 - month是保留的Oracle字词,不要将其用作列名。该解决方案假定日期列包含已截断到月初的日期。 &#34;中的诀窍&#34;在dense_rank last中,当月份是当前月份时,指定一个值(任意值!);默认情况下,分配给所有其他月份的值为NULL,默认情况下以升序排列任何非空值。

如果执行时间很重要,您可能希望测试各种解决方案的效率。

with
     inputs ( id, mth, amount ) as (
       select 1, date '2016-10-01', 20 from dual union all
       select 1, date '2016-08-01', 10 from dual union all
       select 1, date '2016-07-01', 17 from dual union all
       select 2, date '2016-10-01', 30 from dual union all
       select 2, date '2016-09-01', 25 from dual union all
       select 3, date '2016-10-01', 20 from dual union all
       select 4, date '2016-08-01', 45 from dual union all
       select 4, date '2016-06-01', 30 from dual
     )
-- end of TEST DATA - the solution (SQL query) is below this line
select id,
       max(mth) keep(dense_rank last order by
                case when mth = trunc(sysdate, 'mm') then 0 end, mth) as mth,
       max(amount) keep(dense_rank last order by
                case when mth = trunc(sysdate, 'mm') then 0 end, mth) as amount
from inputs
group by id
order by id   -- ORDER BY is optional
;


 ID MTH         AMOUNT
--- ---------- -------
  1 2016-08-01      10
  2 2016-09-01      25
  3 2016-10-01      20
  4 2016-08-01      45

答案 5 :(得分:0)

您可以按照您想要的方向对数据进行排序:

tr min; %b;
te min; %b;