这个月的最后一天,在SQLPLUS中扭曲了

时间:2009-07-15 19:51:39

标签: sql oracle

我希望得到一位专家的帮助。

在SQL SELECT语句中我试图获取去年每月数据的最后一天。 例如,我很容易得到每个月的最后一天并将其加入我的数据表,但问题是,如果该月的最后一天没有数据,则没有返回的数据。我需要的是让SELECT返回最后一天的月份数据。

这可能很容易,但说实话,我的大脑屁开始受伤了。

我附上了下面的选项,用于返回过去12个月中该月最后一天的数据。

提前感谢您的帮助!

SELECT fd.cust_id,fd.server_name,fd.instance_name,
    TRUNC(fd.coll_date) AS coll_date,fd.column_name
FROM super_table fd,
    (SELECT TRUNC(daterange,'MM')-1 first_of_month
    FROM (
    select TRUNC(sysdate-365,'MM') + level as DateRange
    from    dual
    connect by level<=365)
    GROUP BY TRUNC(daterange,'MM')) fom
WHERE fd.cust_id = :CUST_ID
AND fd.coll_date > SYSDATE-400
AND TRUNC(fd.coll_date) = fom.first_of_month
GROUP BY fd.cust_id,fd.server_name,fd.instance_name,
    TRUNC(fd.coll_date),fd.column_name
ORDER BY fd.server_name,fd.instance_name,TRUNC(fd.coll_date)

3 个答案:

答案 0 :(得分:2)

您可能需要对数据进行分组,以便每个月的数据都在组中,然后在组内选择最大日期。子查询可能是:

SELECT MAX(coll_date) AS last_day_of_month
    FROM Super_Table AS fd
    GROUP BY YEAR(coll_date) * 100 + MONTH(coll_date);

这假定存在YEAR()和MONTH()函数以从日期中提取年和月作为整数值。显然,这并不限制日期范围 - 你也可以这样做。如果您没有Oracle中的函数,那么您可以进行某种操作以获得相同的结果。

使用Rhose的信息(谢谢):

SELECT MAX(coll_date) AS last_day_of_month
    FROM Super_Table AS fd
    GROUP BY TO_CHAR(coll_date, 'YYYYMM');

这实现了相同的净结果,将同一日历月中的所有日期放入一个组中,然后确定该组中的最大值。

答案 1 :(得分:1)

将上述部分放在一起,这样的事情对你有用吗?

 SELECT fd.cust_id,
       fd.server_name,
       fd.instance_name,
       TRUNC(fd.coll_date) AS coll_date,
       fd.column_name
  FROM super_table fd,
 WHERE fd.cust_id = :CUST_ID
   AND TRUNC(fd.coll_date) IN (
                                SELECT MAX(TRUNC(coll_date))
                                  FROM super_table
                                 WHERE coll_date > SYSDATE - 400
                                   AND cust_id = :CUST_ID
                                 GROUP BY TO_CHAR(coll_date,'YYYYMM')
                              )
 GROUP BY fd.cust_id,fd.server_name,fd.instance_name,TRUNC(fd.coll_date),fd.column_name
 ORDER BY fd.server_name,fd.instance_name,TRUNC(fd.coll_date)

答案 2 :(得分:1)

如果支持ANSI row_number(),这是另一种方法:

with RevDayRanked(itemDate,rn) as (
  select
    cast(coll_date as date),
    row_number() over (
      partition by datediff(month,coll_date,'2000-01-01') -- rewrite datediff as needed for your platform
      order by coll_date desc
    )
  from super_table
)
  select itemDate
  from RevDayRanked
  where rn = 1;

编号为1的行将在该月的最后一个活动日期的行中进行不确定性选择,因此您不需要区分。如果您希望在这些日期的所有行中使用表格中的信息,请使用rank()天数而不是row_number()超过coll_date值,因此对于上一个活动日期的任何行,都会显示值1月,并选择您需要的其他列:

with RevDayRanked(cust_id, server_name, coll_date, rk) as (
  select
    cust_id, server_name, coll_date,
    rank() over (
      partition by datediff(month,coll_date,'2000-01-01')
      order by cast(coll_date as date) desc
    )
  from super_table
)
  select cust_id, server_name, coll_date
  from RevDayRanked
  where rk = 1;

如果不支持row_number()rank(),则另一种方法(对于上面的第二个查询)。从表格中选择同一月中某一行中没有行的所有行。

select
  cust_id, server_name, coll_date
from super_table as ST1
where not exists (
  select *
  from super_table as ST2
  where datediff(month,ST1.coll_date,ST2.coll_date) = 0
  and cast(ST2.coll_date as date) > cast(ST1.coll_date as date)
)

如果你必须做很多这样的事情,看看你是否可以创建一个包含cast(coll_date as date)的计算列和datediff(month,'2001-01-01',coll_date)月份指标的索引。这将使更多的谓词成为SARG。