2009-07-15 71 views
2

我希望有一位专家帮忙。本月的最后一天,在SQLPLUS中加上扭曲

在一个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) 

回答

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(),而不是在日期的最后一个活动日期上显示值为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()不支持,另一种方法是这样的(上面第二个查询)。从表格中选择表格中没有行的表格中的所有行,这些表格在同一个月的较晚日期中不存在。

如果你要做这种事情很多,看你是否能创造超过持有cast(coll_date as date)计算列的索引,并且像datediff(month,'2001-01-01',coll_date)一个月的指标。这将使更多的谓词SARGs。

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'); 

这实现了相同的净结果是,把所有的日期从相同的日历月成一组,然后确定在该组中存在的最大值。

+0

对于Oracle,您可以使用GROUP BY TO_CHAR(coll_date,'YYYYMM') – Rhose 2009-07-15 20:16:57

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)