SQL查询用于计算每天每个状态中的对象数

时间:2014-11-11 19:04:30

标签: sql oracle

给定一组记录对象进入特定状态的日期的数据库记录,我想生成一个查询,显示在任何特定日期每个状态中有多少个对象。结果将用于生成趋势报告,显示每个州的对象数量如何随时间变化。

我有一个像下面这样的表来记录对象进入特定状态的日期:

ObjID EntryDate  State
----- ---------- -----
    1 2014-11-01   A
    1 2014-11-04   B
    1 2014-11-06   C
    2 2014-11-01   A
    2 2014-11-03   B
    2 2014-11-10   C
    3 2014-11-03   B
    3 2014-11-08   C

有任意数量的对象和状态。

我需要生成一个查询,该查询返回每个日期每个州的对象数。结果如下所示:

Date       State Count
---------- ----- -----
2014-11-01   A       2
2014-11-01   B       0
2014-11-01   C       0
2014-11-02   A       2
2014-11-02   B       0
2014-11-02   C       0
2014-11-03   A       1
2014-11-03   B       2
2014-11-03   C       0
2014-11-04   A       0
2014-11-04   B       3
2014-11-04   C       0
2014-11-05   A       0
2014-11-05   B       3
2014-11-05   C       0
2014-11-06   A       0
2014-11-06   B       2
2014-11-06   C       1
2014-11-07   A       0
2014-11-07   B       2
2014-11-07   C       1
2014-11-08   A       0
2014-11-08   B       1
2014-11-08   C       2
2014-11-09   A       0
2014-11-09   B       1
2014-11-09   C       2
2014-11-10   A       0
2014-11-10   B       0
2014-11-10   C       3

我正在使用Oracle数据库。

我还没能找到符合我案例的例子。以下问题看起来像是要求解决类似但不同的问题:

我们非常感谢您提供的任何帮助或提示。

8 个答案:

答案 0 :(得分:0)

选择EntryDate作为Date,State,Count(Distinct ObjID)作为Count_1从Table_1 按EntryDate分组,州

答案 1 :(得分:0)

SELECT EntryDate AS "Date", State, COUNT(DISTINCT ObjectId) AS "Count" GROUP BY EntryDate, State ORDER BY EntryDate, State;

答案 2 :(得分:0)

由于每个日期都未记录每个州,因此您需要执行CROSS JOIN以获取唯一的状态,然后执行GROUP BY

SELECT EntryDate, 
       C.State, 
       SUM(case when C.state = Table1.state then 1 else 0 end) as Count
FROM Table1
CROSS JOIN ( SELECT DISTINCT State FROM Table1) C
GROUP BY EntryDate, C.State
ORDER BY EntryDate

答案 3 :(得分:0)

我会快速而肮脏地获取数字。您可以选择首选方法。 。 。使用递归CTE,connect by或数字表。因此,以下内容生成日期和状态的所有组合。然后,它使用相关子查询来计算每个日期中每个状态中的对象数:

with n as (
      select rownum - 1 as n
      from table t
     ),
     dates as (
      select mind + n.n
      from (select min(date) as mind, max(date) as maxd from table) t
      where mind + n.n <= maxd
     )
select d.date, s.state,
       (select count(*)
        from (select t2.*, lead(date) over (partition by ObjId order by date) as nextdate
              from table t2
             ) t2
        where d.date >= t2.date and (d.date < t2.nextdate or t2.nextdate is null) and
              d.state = t2.state
       ) as counts
from dates d cross join
     (select distinct state from table t)

答案 4 :(得分:0)

此查询将列出每天输入特定状态的对象数量,假设每个对象仅在一天内更改状态。如果对象每天更改状态超过一次,则需要使用count(distinct objid):

select entrydate, state, count(objid) 
from my_table
group by entrydate, state
order by entrydate, state

但是,您询问每天特定状态中有多少个对象,因此您需要一个非常不同的查询来显示它。由于您仅在示例中提供该特定表,因此我仅使用该表:

select alldatestates.entrydate, alldatestates.state, count(statesbyday.objid)
from
    (
    select alldates.entrydate, allstates.state
    from (select distinct entrydate from mytable) alldates,
         (select distinct state from mytable) allstates
    ) alldatestates
    left join
    (
    select alldates.entrydate, allobjs.objid, (select min(state) as state from mytable t1 
                                          where t1.objid = allobjs.objid and 
                                                t1.entrydate = (select max(entrydate) from mytable t2 
                                                                where t2.objid = t1.objid and
                                                                      t2.entrydate <= alldates.entrydate)) as state
    from (select distinct entrydate from mytable) alldates,
         (select distinct objid from mytable) allobjs
    ) statesbyday
    on alldatestates.entrydate = statesbyday.entrydate and alldatestates.state = statesbyday.state
group by alldatestates.entrydate, alldatestates.state
order by alldatestates.entrydate, alldatestates.state

当然,如果您有一个表用于所有可能的状态,另一个表用于所有可能的对象ID,则此查询将更加简单。

此外,您可能会发现一个比这更简单的查询,但这个有效。缺点是,它可能很快成为优化者的噩梦! :)

答案 5 :(得分:0)

使用SQL SERVER,因为我比较熟悉,但这是我迄今为止所做的:

小提琴示例(SQL SERVER,但唯一的区别应该是我认为的日期函数......):http://sqlfiddle.com/#!3/8b9748/2

WITH zeroThruNine AS (SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9), 
nums AS (SELECT 10*b.n+a.n AS n FROM zeroThruNine a, zeroThruNine b), 
Dates AS (
    SELECT DATEADD(d,n.n,(SELECT MIN(t.EntryDate) FROM @tbl t)) AS Date
    FROM nums n
    WHERE DATEADD(d,n.n,(SELECT MIN(t.EntryDate) FROM @tbl t))<=(SELECT MAX(t.EntryDate) FROM @tbl t)
), Data AS (
    SELECT d.Date, t.ObjID, t.State, ROW_NUMBER() OVER (PARTITION BY t.ObjID, d.Date ORDER BY t.EntryDate DESC) as r
    FROM Dates d, @tbl t
    WHERE d.Date>=t.EntryDate
)
SELECT t.Date, t.State, COUNT(*)
FROM Data t
WHERE t.r=1
GROUP BY t.Date, t.State
ORDER BY t.Date, t.State

首先,开始制作数字表(参见http://web.archive.org/web/20150411042510/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-numbers-table.html)以获取示例。有不同的方法可以在不同的数据库中创建数字表,因此我创建的前两个WITH表达式只是创建数字0到99的视图。我确定还有其他方法,而你可能需要的不仅仅是100个数字(表示您提供的第一个和最后一个日期之间的100个日期)

因此,一旦你到达日期CTE,主要部分是数据CTE

它从Dates cte中找到每个日期,并将其与@tbl表(您的表)的值与在所述日期之后记录的任何状态配对。它还按递减顺序标记状态/每个objid的顺序。这样,在最终查询中,我们可以使用WHERE t.r = 1来获取每个objid每个日期的最大状态

一个问题是,这会获取所有日期的数据,即使没有记录任何日期的数据,但对于零计数,它不会返回任何内容。如果你愿意,你可以将这个结果与不同状态的视图联系起来,并在没有连接的情况下取0

答案 6 :(得分:0)

尝试此查询:

select EntryDate As Date, State, COUNT(ObjID) AS Count from table_name
GROUP BY EntryDate , State 
ORDER BY State

答案 7 :(得分:0)

您也可以尝试使用解析功能:

Select
Date,
State,
count(distinct obj) OVER (PARTITION BY EntryDate, State) count
from table
order by 1;