Oracle SQL - 使用日期函数来改进查询

时间:2012-10-03 23:21:44

标签: sql oracle

我有这个查询

 --Retention by DOC,Users created >= Jan 1,2012--
Select 
One.Date_Of_Concern,
Two.Users, 
One.Retained,
Round(One.Retained/Two.Users,4) as Perc_Retained
From
(
Select 
To_Date('2012-sep-09','yyyy-mon-dd')As Date_Of_Concern,
Count(P.Player_Id) As Retained
From Player P
Where
Trunc(P.Create_Dtime) >= To_Date('2012-Jan-01','yyyy-mon-dd')
 And
(To_Date('2012-sep-09','yyyy-mon-dd')-Trunc(P.Init_Dtime))<=7
 ) One
Inner Join
(
Select 
To_Date('2012-sep-09','yyyy-mon-dd')As Date_Of_Concern,
Count(P.Player_Id) As Users
From Player P
Where
Trunc(P.Create_Dtime) >= To_Date('2012-Jan-01','yyyy-mon-dd')
) Two On One.Date_Of_Concern = Two.Date_Of_Concern

给了我一行的结果:

Date_Of_Concern     USERS     RETAINED     PERC_RETAINED
09-Sep-12            449773    78983        0.1756

我想通过添加某种日期更改方法来改进此查询。这样,我不必每次都为09-sep-12,10-sep-12,11-sep-12运行查询,依此类推。相反,它将显示在同一个查询中,如下所示:

Date_Of_Concern     USERS     RETAINED     PERC_RETAINED
09-Sep-12            449773    48783        0.1756
10-Sep-12            449773    46777        0.1600
11-Sep-12            440773    44852        0.1500
12-Sep-12            349773    42584         0.1400

2 个答案:

答案 0 :(得分:1)

嗯,根据给定的信息,我不知道您是否有任何桌子可以加入并带上这些日期。但是,如果你不这样做,你可以试试这个:

我们必须生成行并以顺序形式重现日期。但首先,让我们看一下如何生成行:

生成5行:

SELECT rownum 
FROM dual 
CONNECT BY LEVEL <= 5;

 ROWNUM
----------
         1
         2
         3
         4
         5

现在,应用它来重现日期的数据源:

SELECT to_date('2012-sep-09','yyyy-mon-dd') + (rownum -1) as Date_Of_Concern
FROM dual 
CONNECT BY LEVEL <= 5;

 Date_Of_Concern
----------
 2012-sep-09
 2012-sep-10
 2012-sep-11
 2012-sep-12
 2012-sep-13

显然你需要一个开始日期。此外,数字5必须由您需要的日期数替换,它可以是日期范围,如

SELECT to_date('2012-sep-09','yyyy-mon-dd') + (rownum -1) date
FROM dual 
CONNECT BY LEVEL <= (to_date('2012-sep-20','yyyy-mon-dd') - to_date('2012-sep-09','yyyy-mon-dd'));

好的,现在最终结果如下:

SELECT  both.Date_Of_Concern,
        both.Retained,
        both.Users,
        Round(both.Retained/both.Users,4) as Perc_Retained
  FROM (select Date_Of_Concern,
              (Select Count(P.Player_Id) As Retained
                From Player P
                Where Trunc(P.Create_Dtime) >= To_Date('2012-Jan-01','yyyy-mon-dd')
                  And (Date_Of_Concern-Trunc(P.Init_Dtime))<=7) Retained,
              (Select Count(P.Player_Id) As Users
                    From Player P
                    Where Trunc(P.Create_Dtime) >= To_Date('2012-Jan-01','yyyy-mon-dd')
                ) Users
          from (SELECT to_date('2012-sep-09','yyyy-mon-dd') + (rownum -1) Date_Of_Concern,
                FROM dual 
                CONNECT BY LEVEL <= 5)) both

答案 1 :(得分:0)

我感觉您的查询可以简化很多。这是尝试从2012年初开始逐日列出。取决于您正在寻找的范围。

SELECT date_of_concern
      ,Running_Total_Users AS Users
      ,Running_Total_Retained As Retained
      ,ROUND(Running_Total_Retained / Running_Total_Users, 4) AS Perc_Retained

  FROM ( SELECT date_of_concern

               ,SUM(Users) OVER( ORDER BY date_of_concern
                                 ROWS BETWEEN UNBOUNDED PRECEDING
                                          AND CURRENT ROW ) AS Running_Total_Users

               ,SUM(Retained) OVER( ORDER BY date_of_concern
                                 ROWS BETWEEN UNBOUNDED PRECEDING
                                          AND CURRENT ROW ) AS Running_Total_Retained

           FROM ( SELECT TRUNC(Create_Dtime) date_of_concern
                        ,COUNT(Player_Id) Users
                        ,SUM( CASE WHEN (TRUNC(Create_Dtime) - TRUNC(Init_Dtime)) <= 7 THEN 1 ELSE 0 END ) AS Retained
                    FROM player ON ( TRUNC(.Create_Dtime) >= TO_DATE('2012', 'YYYY') )
                )
        )

最内部查询是尝试重新编写从第1天(2012年1月1日)算起的已发布查询。然后,下一个包装器应该为每个后续日运行总计。最后的包装器是启用Perc_Retained。当然未经测试完成:)